home *** CD-ROM | disk | FTP | other *** search
/ Game Power / Game Power Vol. 1 (HEPP Computer) (1995).iso / S053 / DISK2 / EDITOBJ.C < prev    next >
C/C++ Source or Header  |  1994-04-27  |  72KB  |  2,391 lines

  1. /*
  2.    Doom Editor Utility, by Brendon Wyber and Raphaël Quinet.
  3.  
  4.    You are allowed to use any parts of this code in another program, as
  5.    long as you give credits to the authors in the documentation and in
  6.    the program itself.  Read the file README.1ST for more information.
  7.  
  8.    This program comes with absolutely no warranty.
  9.  
  10.    EDITOBJ.C - object editing routines.
  11. */
  12.  
  13. /* the includes */
  14. #include "deu.h"
  15. #include "levels.h"
  16.  
  17.  
  18. /*
  19.    display the information about one object
  20. */
  21.  
  22. void DisplayObjectInfo( int objtype, int objnum) /* SWAP! */
  23. {
  24.    char texname[ 9];
  25.    int  tag, n;
  26.    int  sd1, sd2, s1, s2;
  27.    int  x0, y0;
  28.  
  29.    ObjectsNeeded( objtype, 0);
  30.    switch (objtype)
  31.    {
  32.    case OBJ_THINGS:
  33.       x0 = 0;
  34.       y0 = ScrMaxY - 60;
  35.       if (InfoShown)
  36.      y0 -= 13;
  37.       DrawScreenBox3D( x0, y0, x0 + 260, y0 + 60);
  38.       if (objnum < 0)
  39.       {
  40.      DrawScreenText( x0 + 60, y0 + 20, "Use the cursor to");
  41.      DrawScreenText( x0 + 72, y0 + 30, "select a Thing  ");
  42.      break;
  43.       }
  44.       SetColor( YELLOW);
  45.       DrawScreenText( x0 + 5, y0 + 5, "Selected Thing (#%d)", objnum);
  46.       SetColor( BLACK);
  47.       DrawScreenText( -1, y0 + 20, "Coordinates:  (%d, %d)", Things[ objnum].xpos, Things[ objnum].ypos);
  48.       DrawScreenText( -1, -1, "Type:         %s", GetThingName( Things[ objnum].type));
  49.       DrawScreenText( -1, -1, "Angle:        %s", GetAngleName( Things[ objnum].angle));
  50.       DrawScreenText( -1, -1, "Appears when: %s", GetWhenName( Things[ objnum].when));
  51.       break;
  52.    case OBJ_LINEDEFS:
  53.       x0 = 0;
  54.       y0 = ScrMaxY - 80;
  55.       if (InfoShown)
  56.      y0 -= 13;
  57.       DrawScreenBox3D(   x0, y0, x0 + 218, y0 + 80);
  58.       if (objnum >= 0)
  59.       {
  60.      SetColor( YELLOW);
  61.      DrawScreenText( x0 + 5, y0 + 5, "Selected LineDef (#%d)", objnum);
  62.      SetColor( BLACK);
  63.      DrawScreenText( -1, y0 + 20, "Vertexes:    (#%d, #%d)", LineDefs[ objnum].start, LineDefs[ objnum].end);
  64.      DrawScreenText( -1, -1, "Flags:%3d    %s", LineDefs[ objnum].flags, GetLineDefFlagsName( LineDefs[ objnum].flags));
  65.      DrawScreenText( -1, -1, "Type: %3d %s", LineDefs[ objnum].type, GetLineDefTypeName( LineDefs[ objnum].type));
  66.      sd1 = LineDefs[ objnum].sidedef1;
  67.      sd2 = LineDefs[ objnum].sidedef2;
  68.      tag = LineDefs[ objnum].tag;
  69.      ObjectsNeeded( OBJ_SIDEDEFS, OBJ_SECTORS, 0);
  70.      if (tag > 0)
  71.      {
  72.         for (n = 0; n < NumSectors; n++)
  73.            if (Sectors[ n].tag == tag)
  74.           break;
  75.      }
  76.      else
  77.         n = NumSectors;
  78.      if (n < NumSectors)
  79.         DrawScreenText( -1, -1, "Sector tag:  %d (#%d)", tag, n);
  80.      else
  81.         DrawScreenText( -1, -1, "Sector tag:  %d (none)", tag);
  82.      DrawScreenText( -1, -1, "1st SideDef: #%d", sd1);
  83.      DrawScreenText( -1, -1, "2nd SideDef: #%d", sd2);
  84.      if (sd1 >= 0)
  85.         s1 = SideDefs[ sd1].sector;
  86.      else
  87.         s1 = -1;
  88.      if (sd2 >= 0)
  89.         s2 = SideDefs[ sd2].sector;
  90.      else
  91.         s2 = -1;
  92.       }
  93.       else
  94.       {
  95.     SetColor( DARKGRAY);
  96.     DrawScreenText( x0 + 25, y0 + 35, "(No LineDef selected)");
  97.       }
  98.       x0 = 220;
  99.       y0 = ScrMaxY - 80;
  100.       if (InfoShown)
  101.      y0 -= 13;
  102.       DrawScreenBox3D( x0, y0, x0 + 218, y0 + 80);
  103.       if (objnum >= 0 && sd1 >= 0)
  104.       {
  105.      SetColor( YELLOW);
  106.      DrawScreenText( x0 + 5, y0 + 5, "First SideDef (#%d)", sd1);
  107.      SetColor( BLACK);
  108.      texname[ 8] = '\0';
  109.      strncpy( texname, SideDefs[ sd1].tex3, 8);
  110.      DrawScreenText( -1, y0 + 20, "Normal texture: %s", texname);
  111.      strncpy( texname, SideDefs[ sd1].tex1, 8);
  112.      if (s1 >= 0 && s2 >= 0 && Sectors[ s1].ceilh > Sectors[ s2].ceilh)
  113.      {
  114.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  115.            SetColor( RED);
  116.      }
  117.      else
  118.         SetColor( DARKGRAY);
  119.      DrawScreenText( -1, -1, "Upper texture:  %s", texname);
  120.      SetColor( BLACK);
  121.      strncpy( texname, SideDefs[ sd1].tex2, 8);
  122.      if (s1 >= 0 && s2 >= 0 && Sectors[ s1].floorh < Sectors[ s2].floorh)
  123.      {
  124.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  125.            SetColor( RED);
  126.      }
  127.      else
  128.         SetColor( DARKGRAY);
  129.      DrawScreenText( -1, -1, "Lower texture:  %s", texname);
  130.      SetColor( BLACK);
  131.      DrawScreenText( -1, -1, "Tex. X offset:  %d", SideDefs[ sd1].xoff);
  132.      DrawScreenText( -1, -1, "Tex. Y offset:  %d", SideDefs[ sd1].yoff);
  133.      DrawScreenText( -1, -1, "Sector:         #%d", s1);
  134.       }
  135.       else
  136.       {
  137.     SetColor( DARKGRAY);
  138.     DrawScreenText( x0 + 25, y0 + 35, "(No first SideDef)");
  139.       }
  140.       x0 = 440;
  141.       y0 = ScrMaxY - 80;
  142.       if (InfoShown)
  143.      y0 -= 13;
  144.       DrawScreenBox3D( x0, y0, x0 + 200, y0 + 80);
  145.       if (objnum >= 0 && sd2 >= 0)
  146.       {
  147.      SetColor( YELLOW);
  148.      DrawScreenText( x0 + 5, y0 + 5, "Second SideDef (#%d)", sd2);
  149.      SetColor( BLACK);
  150.      texname[ 8] = '\0';
  151.      strncpy( texname, SideDefs[ sd2].tex3, 8);
  152.      DrawScreenText( -1, y0 + 20, "Normal texture: %s", texname);
  153.      strncpy( texname, SideDefs[ sd2].tex1, 8);
  154.      if (s1 >= 0 && s2 >= 0 && Sectors[ s2].ceilh > Sectors[ s1].ceilh)
  155.      {
  156.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  157.            SetColor( RED);
  158.      }
  159.      else
  160.         SetColor( DARKGRAY);
  161.      DrawScreenText( -1, -1, "Upper texture:  %s", texname);
  162.      SetColor( BLACK);
  163.      strncpy( texname, SideDefs[ sd2].tex2, 8);
  164.      if (s1 >= 0 && s2 >= 0 && Sectors[ s2].floorh < Sectors[ s1].floorh)
  165.      {
  166.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  167.            SetColor( RED);
  168.      }
  169.      else
  170.         SetColor( DARKGRAY);
  171.      DrawScreenText( -1, -1, "Lower texture:  %s", texname);
  172.      SetColor( BLACK);
  173.      DrawScreenText( -1, -1, "Tex. X offset:  %d", SideDefs[ sd2].xoff);
  174.      DrawScreenText( -1, -1, "Tex. Y offset:  %d", SideDefs[ sd2].yoff);
  175.      DrawScreenText( -1, -1, "Sector:         #%d", s2);
  176.       }
  177.       else
  178.       {
  179.     SetColor( DARKGRAY);
  180.     DrawScreenText( x0 + 25, y0 + 35, "(No second SideDef)");
  181.       }
  182.       break;
  183.    case OBJ_VERTEXES:
  184.       x0 = 0;
  185.       y0 = ScrMaxY - 30;
  186.       if (InfoShown)
  187.      y0 -= 13;
  188.       DrawScreenBox3D( x0, y0, x0 + 220, y0 + 30);
  189.       if (objnum < 0)
  190.       {
  191.      SetColor( DARKGRAY);
  192.      DrawScreenText( x0 + 30, y0 + 12, "(No Vertex selected)");
  193.      break;
  194.       }
  195.       SetColor( YELLOW);
  196.       DrawScreenText( x0 + 5, y0 + 5, "Selected Vertex (#%d)", objnum);
  197.       SetColor( BLACK);
  198.       DrawScreenText( -1, y0 + 20, "Coordinates: (%d, %d)", Vertexes[ objnum].x, Vertexes[ objnum].y);
  199.       break;
  200.    case OBJ_SECTORS:
  201.       x0 = 0;
  202.       y0 = ScrMaxY - 90;
  203.       if (InfoShown)
  204.      y0 -= 13;
  205.       DrawScreenBox3D( x0, y0, x0 + 255, y0 + 90);
  206.       if (objnum < 0)
  207.       {
  208.     SetColor( DARKGRAY);
  209.     DrawScreenText( x0 + 48, y0 + 35, "(No Sector selected)");
  210.     break;
  211.       }
  212.       SetColor( YELLOW);
  213.       DrawScreenText( x0 + 5, y0 + 5, "Selected Sector (#%d)", objnum);
  214.       SetColor( BLACK);
  215.       DrawScreenText( -1, y0 + 20, "Floor height:    %d", Sectors[ objnum].floorh);
  216.       DrawScreenText( -1, -1, "Ceiling height:  %d", Sectors[ objnum].ceilh);
  217.       texname[ 8] = '\0';
  218.       strncpy( texname, Sectors[ objnum].floort, 8);
  219.       DrawScreenText( -1, -1, "Floor texture:   %s", texname);
  220.       strncpy( texname, Sectors[ objnum].ceilt, 8);
  221.       DrawScreenText( -1, -1, "Ceiling texture: %s", texname);
  222.       DrawScreenText( -1, -1, "Light level:     %d", Sectors[ objnum].light);
  223.       DrawScreenText( -1, -1, "Type: %3d        %s", Sectors[ objnum].special, GetSectorTypeName( Sectors[ objnum].special));
  224.       tag = Sectors[ objnum].tag;
  225.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  226.       if (tag == 0)
  227.      n = NumLineDefs;
  228.       else
  229.      for (n = 0; n < NumLineDefs; n++)
  230.         if (LineDefs[ n].tag == tag)
  231.            break;
  232.       if (n < NumLineDefs)
  233.      DrawScreenText( -1, -1, "LineDef tag:     %d (#%d)", tag, n);
  234.       else if (tag == 99 || tag == 999)
  235.      DrawScreenText( -1, -1, "LineDef tag:     %d (stairs?)", tag);
  236.       else if (tag == 666)
  237.      DrawScreenText( -1, -1, "LineDef tag:     %d (lower@end)", tag);
  238.       else
  239.      DrawScreenText( -1, -1, "LineDef tag:     %d (none)", tag);
  240.       break;
  241.    }
  242. }
  243.  
  244.  
  245.  
  246. /*
  247.    display and execute a "things" menu
  248. */
  249.  
  250. int DisplayThingsMenu( int x0, int y0, char *menutitle, ...)
  251. {
  252.    va_list args;
  253.    int     val, num;
  254.    int     thingid[ 30];
  255.    char   *menustr[ 30];
  256.    int     dummy[ 30];
  257.  
  258.    /* put the va_args in the menustr table */
  259.    num = 0;
  260.    va_start( args, menutitle);
  261.    while ((num < 30) && ((thingid[ num] = va_arg( args, int)) >= 0))
  262.    {
  263.       menustr[ num] = GetThingName( thingid[ num]);
  264.       num++;
  265.    }
  266.    va_end( args);
  267.  
  268.    /* display the menu */
  269.    val = DisplayMenuArray( x0, y0, menutitle, num, NULL, menustr, dummy) - 1;
  270.  
  271.    /* return the thing id, if valid */
  272.    if (val < 0 || val >= num)
  273.      return -1;
  274.    return thingid[ val];
  275. }
  276.  
  277.  
  278.  
  279. /*
  280.    display and execute a "linedef type" menu
  281. */
  282.  
  283. int DisplayLineDefTypeMenu( int x0, int y0, char *menutitle, ...)
  284. {
  285.    va_list args;
  286.    int     val, num;
  287.    int     typeid[ 30];
  288.    char   *menustr[ 30];
  289.    int     dummy[ 30];
  290.  
  291.    /* put the va_args in the menustr table */
  292.    num = 0;
  293.    va_start( args, menutitle);
  294.    while ((num < 30) && ((typeid[ num] = va_arg( args, int)) >= 0))
  295.    {
  296.       menustr[ num] = GetLineDefTypeLongName( typeid[ num]);
  297.       num++;
  298.    }
  299.    va_end( args);
  300.  
  301.    /* display the menu */
  302.    val = DisplayMenuArray( x0, y0, menutitle, num, NULL, menustr, dummy) - 1;
  303.  
  304.    /* return the thing id, if valid */
  305.    if (val < 0 || val >= num)
  306.      return -1;
  307.    return typeid[ val];
  308. }
  309.  
  310.  
  311.  
  312. /*
  313.    ask for an object number and check for maximum valid number
  314.    (this is just like InputIntegerValue, but with a different prompt)
  315. */
  316.  
  317. int InputObjectNumber( int x0, int y0, int objtype, int curobj)
  318. {
  319.    int val, key;
  320.    char prompt[ 80];
  321.  
  322.    if (UseMouse)
  323.       HideMousePointer();
  324.    sprintf( prompt, "Enter a %s number between 0 and %d:", GetObjectTypeName( objtype), GetMaxObjectNum( objtype));
  325.    if (x0 < 0)
  326.       x0 = (ScrMaxX - 25 - 8 * strlen( prompt)) / 2;
  327.    if (y0 < 0)
  328.       y0 = (ScrMaxY - 55) / 2;
  329.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * strlen( prompt), y0 + 55);
  330.    SetColor( WHITE);
  331.    DrawScreenText( x0 + 10, y0 + 8, prompt);
  332.    val = curobj;
  333.    while (((key = InputInteger( x0 + 10, y0 + 28, &val, 0, GetMaxObjectNum( objtype))) & 0x00FF) != 0x000D && (key & 0x00FF) != 0x001B)
  334.       Beep();
  335.    if (UseMouse)
  336.       ShowMousePointer();
  337.    return val;
  338. }
  339.  
  340.  
  341.  
  342. /*
  343.    ask for an object number and display a warning message
  344. */
  345.  
  346. int InputObjectXRef( int x0, int y0, int objtype, Bool allownone, int curobj)
  347. {
  348.    int val, key;
  349.    char prompt[ 80];
  350.  
  351.    if (UseMouse)
  352.       HideMousePointer();
  353.    sprintf( prompt, "Enter a %s number between 0 and %d%c", GetObjectTypeName( objtype), GetMaxObjectNum( objtype), allownone ? ',' : ':');
  354.    val = strlen( prompt);
  355.    if (val < 40)
  356.       val = 40;
  357.    if (x0 < 0)
  358.       x0 = (ScrMaxX - 25 - 8 * val) / 2;
  359.    if (y0 < 0)
  360.       y0 = (ScrMaxY - (allownone ? 85 : 75)) / 2;
  361.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * val, y0 + (allownone ? 85 : 75));
  362.    SetColor( WHITE);
  363.    DrawScreenText( x0 + 10, y0 + 8, prompt);
  364.    if (allownone)
  365.       DrawScreenText( x0 + 10, y0 + 18, "or -1 for none:");
  366.    SetColor( RED);
  367.    DrawScreenText( x0 + 10, y0 + (allownone ? 60 : 50), "Warning: modifying the cross-references");
  368.    DrawScreenText( x0 + 10, y0 + (allownone ? 70 : 60), "between some objects may crash the game.");
  369.    val = curobj;
  370.    while (((key = InputInteger( x0 + 10, y0 + (allownone ? 38 : 28), &val, allownone ? -1 : 0, GetMaxObjectNum( objtype))) & 0x00FF) != 0x000D && (key & 0x00FF) != 0x001B)
  371.       Beep();
  372.    if (UseMouse)
  373.       ShowMousePointer();
  374.    return val;
  375. }
  376.  
  377.  
  378.  
  379. /*
  380.    ask for two vertex numbers and check for maximum valid number
  381. */
  382.  
  383. Bool Input2VertexNumbers( int x0, int y0, char *prompt1, int *v1, int *v2)
  384. {
  385.    int  val, key;
  386.    int  maxlen, first;
  387.    Bool ok;
  388.    char prompt2[ 80];
  389.  
  390.    if (UseMouse)
  391.       HideMousePointer();
  392.    sprintf( prompt2, "Enter two numbers between 0 and %d:", NumVertexes - 1);
  393.    if (strlen( prompt1) > strlen( prompt2))
  394.       maxlen = strlen( prompt1);
  395.    else
  396.       maxlen = strlen( prompt2);
  397.    if (x0 < 0)
  398.       x0 = (ScrMaxX - 25 - 8 * maxlen) / 2;
  399.    if (y0 < 0)
  400.       y0 = (ScrMaxY - 75) / 2;
  401.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * maxlen, y0 + 75);
  402.    DrawScreenText( x0 + 10, y0 + 36, "From this Vertex");
  403.    DrawScreenText( x0 + 180, y0 + 36, "To this Vertex");
  404.    SetColor( WHITE);
  405.    DrawScreenText( x0 + 10, y0 + 8, prompt1);
  406.    DrawScreenText( x0 + 10, y0 + 18, prompt2);
  407.    first = TRUE;
  408.    key = 0;
  409.    for (;;)
  410.    {
  411.       ok = TRUE;
  412.       DrawScreenBox3D( x0 + 10, y0 + 48, x0 + 71, y0 + 61);
  413.       if (*v1 < 0 || *v1 >= NumVertexes)
  414.       {
  415.      SetColor( DARKGRAY);
  416.      ok = FALSE;
  417.       }
  418.       DrawScreenText( x0 + 14, y0 + 51, "%d", *v1);
  419.       DrawScreenBox3D( x0 + 180, y0 + 48, x0 + 241, y0 + 61);
  420.       if (*v2 < 0 || *v2 >= NumVertexes)
  421.       {
  422.      SetColor( DARKGRAY);
  423.      ok = FALSE;
  424.       }
  425.       DrawScreenText( x0 + 184, y0 + 51, "%d", *v2);
  426.       if (first)
  427.      key = InputInteger( x0 + 10, y0 + 48, v1, 0, NumVertexes - 1);
  428.       else
  429.      key = InputInteger( x0 + 180, y0 + 48, v2, 0, NumVertexes - 1);
  430.       if ((key & 0xFF00) == 0x4B00 || (key & 0xFF00) == 0x4D00 || (key & 0x00FF) == 0x0009 || (key & 0xFF00) == 0x0F00)
  431.      first = !first;
  432.       else if ((key & 0x00FF) == 0x001B)
  433.      break;
  434.       else if ((key & 0x00FF) == 0x000D)
  435.       {
  436.      if (first)
  437.         first = FALSE;
  438.      else if (ok)
  439.         break;
  440.      else
  441.         Beep();
  442.       }
  443.       else
  444.      Beep();
  445.    }
  446.    if (UseMouse)
  447.       ShowMousePointer();
  448.    return ((key & 0x00FF) == 0x000D);
  449. }
  450.  
  451.  
  452.  
  453. /*
  454.    edit an object or a group of objects
  455. */
  456.  
  457. void EditObjectsInfo( int x0, int y0, int objtype, SelPtr obj) /* SWAP! */
  458. {
  459.    char  *menustr[ 30];
  460.    int    dummy[ 30];
  461.    char   texname[ 9];
  462.    int    n, val;
  463.    SelPtr cur, sdlist;
  464.  
  465.    ObjectsNeeded( objtype, 0);
  466.    if (obj == NULL)
  467.       return;
  468.    switch (objtype)
  469.    {
  470.    case OBJ_THINGS:
  471.       for (n = 0; n < 6; n++)
  472.      menustr[ n] = GetMemory( 60);
  473.       sprintf( menustr[ 5], "Edit Thing #%d", obj->objnum);
  474.       sprintf( menustr[ 0], "Change Type          (Current: %s)", GetThingName( Things[ obj->objnum].type));
  475.       sprintf( menustr[ 1], "Change Angle         (Current: %s)", GetAngleName( Things[ obj->objnum].angle));
  476.       sprintf( menustr[ 2], "Change When Appears  (Current: %s)", GetWhenName( Things[ obj->objnum].when));
  477.       sprintf( menustr[ 3], "Change X position    (Current: %d)", Things[ obj->objnum].xpos);
  478.       sprintf( menustr[ 4], "Change Y position    (Current: %d)", Things[ obj->objnum].ypos);
  479.       val = DisplayMenuArray( x0, y0, menustr[ 5], 5, NULL, menustr, dummy);
  480.       for (n = 0; n < 6; n++)
  481.      FreeMemory( menustr[ n]);
  482.       switch (val)
  483.       {
  484.       case 1:
  485.      switch (DisplayMenu( x0 + 42, y0 + 34, "Select Class",
  486.                   "Player",
  487.                   "Enemy",
  488.                   "Weapon",
  489.                   "Bonus",
  490.                   "Decoration",
  491.                   "Decoration (light sources)",
  492.                   "Decoration (dead bodies)",
  493.                   "Decoration (hanging bodies)",
  494.                   "Teleport landing",
  495.                   "(Enter a decimal value)",
  496.                   NULL))
  497.      {
  498.      case 1:
  499.         val = DisplayThingsMenu( x0 + 84, y0 + 68, "Select Start Position Type",
  500.                      THING_PLAYER1,
  501.                      THING_PLAYER2,
  502.                      THING_PLAYER3,
  503.                      THING_PLAYER4,
  504.                      THING_DEATHMATCH,
  505.                      -1);
  506.         break;
  507.  
  508.      case 2:
  509.         val = DisplayThingsMenu( x0 + 84, y0 + 78, "Select Enemy",
  510.                      THING_TROOPER,
  511.                      THING_SARGEANT,
  512.                      THING_IMP,
  513.                      THING_DEMON,
  514.                      THING_SPECTOR,
  515.                      THING_BARON,
  516.                      THING_LOSTSOUL,
  517.                      THING_CACODEMON,
  518.                      THING_CYBERDEMON,
  519.                      THING_SPIDERBOSS,
  520.                      -1);
  521.         break;
  522.  
  523.      case 3:
  524.         val = DisplayThingsMenu( x0 + 84, y0 + 88, "Select Weapon",
  525.                      THING_SHOTGUN,
  526.                      THING_CHAINGUN,
  527.                      THING_LAUNCHER,
  528.                      THING_PLASMAGUN,
  529.                      THING_CHAINSAW,
  530.                      THING_SHELLS,
  531.                      THING_AMMOCLIP,
  532.                      THING_ROCKET,
  533.                      THING_ENERGYCELL,
  534.                      THING_BFG9000,
  535.                      THING_SHELLBOX,
  536.                      THING_AMMOBOX,
  537.                      THING_ROCKETBOX,
  538.                      THING_ENERGYPACK,
  539.                      THING_BACKPACK,
  540.                      -1);
  541.         break;
  542.  
  543.      case 4:
  544.         val = DisplayThingsMenu( x0 + 84, y0 + 98, "Select Bonus",
  545.                      THING_REDCARD,
  546.                      THING_YELLOWCARD,
  547.                      THING_BLUECARD,
  548.                      THING_REDSKULLKEY,
  549.                      THING_YELLOWSKULLKEY,
  550.                      THING_BLUESKULLKEY,
  551.                      THING_ARMBONUS1,
  552.                      THING_GREENARMOR,
  553.                      THING_BLUEARMOR,
  554.                      THING_HLTBONUS1,
  555.                      THING_STIMPACK,
  556.                      THING_MEDKIT,
  557.                      THING_SOULSPHERE,
  558.                      THING_BLURSPHERE,
  559.                      THING_MAP,
  560.                      THING_RADSUIT,
  561.                      THING_LITEAMP,
  562.                      THING_BESERK,
  563.                      THING_INVULN,
  564.                      -1);
  565.         break;
  566.  
  567.      case 5:
  568.         val = DisplayThingsMenu( x0 + 84, y0 + 108, "Select Decoration",
  569.                      THING_BARREL,
  570.                      THING_TECHCOLUMN,
  571.                      THING_TGREENPILLAR,
  572.                      THING_TREDPILLAR,
  573.                      THING_SGREENPILLAR,
  574.                      THING_SREDPILLAR,
  575.                      THING_PILLARHEART,
  576.                      THING_PILLARSKULL,
  577.                      THING_EYEINSYMBOL,
  578.                      THING_BROWNSTUB,
  579.                      THING_GREYTREE,
  580.                      THING_BROWNTREE,
  581.                      -1);
  582.         break;
  583.  
  584.      case 6:
  585.         val = DisplayThingsMenu( x0 + 84, y0 + 118, "Select Decoration",
  586.                      THING_CANDLE,
  587.                      THING_LAMP,
  588.                      THING_CANDELABRA,
  589.                      THING_TBLUETORCH,
  590.                      THING_TGREENTORCH,
  591.                      THING_TREDTORCH,
  592.                      THING_SBLUETORCH,
  593.                      THING_SGREENTORCH,
  594.                      THING_SREDTORCH,
  595.                      -1);
  596.         break;
  597.  
  598.      case 7:
  599.         val = DisplayThingsMenu( x0 + 84, y0 + 128, "Select Decoration",
  600.                      THING_DEADPLAYER,
  601.                      THING_DEADTROOPER,
  602.                      THING_DEADSARGEANT,
  603.                      THING_DEADIMP,
  604.                      THING_DEADDEMON,
  605.                      THING_DEADCACODEMON,
  606.                      THING_BONES,
  607.                      THING_BONES2,
  608.                      THING_POOLOFBLOOD,
  609.                      THING_SKULLTOPPOLE,
  610.                      THING_HEADSKEWER,
  611.                      THING_PILEOFSKULLS,
  612.                      THING_IMPALEDBODY,
  613.                      THING_IMPALEDBODY2,
  614.                      THING_SKULLSINFLAMES,
  615.                      -1);
  616.         break;
  617.  
  618.      case 8:
  619.         val = DisplayThingsMenu( x0 + 84, y0 + 138, "Select Decoration",
  620.                      THING_HANGINGSWAYING,
  621.                      THING_HANGINGARMSOUT,
  622.                      THING_HANGINGONELEG,
  623.                      THING_HANGINGTORSO,
  624.                      THING_HANGINGLEG,
  625.                      THING_HANGINGSWAYING2,
  626.                      THING_HANGINGARMSOUT2,
  627.                      THING_HANGINGONELEG2,
  628.                      THING_HANGINGTORSO2,
  629.                      THING_HANGINGLEG2,
  630.                      -1);
  631.         break;
  632.  
  633.      case 9:
  634.         val = THING_TELEPORT;
  635.         break;
  636.  
  637.      case 10:
  638.         val = InputIntegerValue( x0 + 84, y0 + 158, 0, 9999, Things[ obj->objnum].type);
  639.         break;
  640.  
  641.      default:
  642.         Beep();
  643.         return;
  644.      }
  645.      if (val >= 0)
  646.      {
  647.         for (cur = obj; cur; cur = cur->next)
  648.            Things[ cur->objnum].type = val;
  649.         MadeChanges = TRUE;
  650.      }
  651.      break;
  652.  
  653.       case 2:
  654.      switch (DisplayMenu( x0 + 42, y0 + 44, "Select Angle",
  655.                   "North",
  656.                   "NorthEast",
  657.                   "East",
  658.                   "SouthEast",
  659.                   "South",
  660.                   "SouthWest",
  661.                   "West",
  662.                   "NorthWest",
  663.                   NULL))
  664.      {
  665.      case 1:
  666.         for (cur = obj; cur; cur = cur->next)
  667.            Things[ cur->objnum].angle = 90;
  668.         MadeChanges = TRUE;
  669.         break;
  670.      case 2:
  671.         for (cur = obj; cur; cur = cur->next)
  672.            Things[ cur->objnum].angle = 45;
  673.         MadeChanges = TRUE;
  674.         break;
  675.      case 3:
  676.         for (cur = obj; cur; cur = cur->next)
  677.            Things[ cur->objnum].angle = 0;
  678.         MadeChanges = TRUE;
  679.         break;
  680.      case 4:
  681.         for (cur = obj; cur; cur = cur->next)
  682.            Things[ cur->objnum].angle = 315;
  683.         MadeChanges = TRUE;
  684.         break;
  685.      case 5:
  686.         for (cur = obj; cur; cur = cur->next)
  687.            Things[ cur->objnum].angle = 270;
  688.         MadeChanges = TRUE;
  689.         break;
  690.      case 6:
  691.         for (cur = obj; cur; cur = cur->next)
  692.            Things[ cur->objnum].angle = 225;
  693.         MadeChanges = TRUE;
  694.         break;
  695.      case 7:
  696.         for (cur = obj; cur; cur = cur->next)
  697.            Things[ cur->objnum].angle = 180;
  698.         MadeChanges = TRUE;
  699.         break;
  700.      case 8:
  701.         for (cur = obj; cur; cur = cur->next)
  702.            Things[ cur->objnum].angle = 135;
  703.         MadeChanges = TRUE;
  704.         break;
  705.      }
  706.      break;
  707.  
  708.       case 3:
  709.      val = DisplayMenu( x0 + 42, y0 + 54, "Choose the difficulty level(s)",
  710.                 "D12          (Easy only)",
  711.                 "D3           (Medium only)",
  712.                 "D12, D3      (Easy and Medium)",
  713.                 "D45          (Hard only)",
  714.                 "D12, D45     (Easy and Hard)",
  715.                 "D3, D45      (Medium and Hard)",
  716.                 "D12, D3, D45 (Easy, Medium, Hard)",
  717.                 "Toggle \"Deaf/Ambush\" bit",
  718.                 "Toggle \"Multi-player only\" bit",
  719.                 "(Enter a decimal value)",
  720.                 NULL);
  721.      switch (val)
  722.      {
  723.      case 1:
  724.      case 2:
  725.      case 3:
  726.      case 4:
  727.      case 5:
  728.      case 6:
  729.      case 7:
  730.         for (cur = obj; cur; cur = cur->next)
  731.            Things[ cur->objnum].when = (Things[ cur->objnum].when & 0x18) | val;
  732.         MadeChanges = TRUE;
  733.         break;
  734.      case 8:
  735.         for (cur = obj; cur; cur = cur->next)
  736.            Things[ cur->objnum].when ^= 0x08;
  737.         MadeChanges = TRUE;
  738.         break;
  739.      case 9:
  740.         for (cur = obj; cur; cur = cur->next)
  741.            Things[ cur->objnum].when ^= 0x10;
  742.         MadeChanges = TRUE;
  743.         break;
  744.      case 10:
  745.         val = InputIntegerValue( x0 + 84, y0 + 158, 1, 31, Things[ obj->objnum].when);
  746.         if (val > 0)
  747.         {
  748.            for (cur = obj; cur; cur = cur->next)
  749.           Things[ cur->objnum].when = val;
  750.            MadeChanges = TRUE;
  751.         }
  752.         break;
  753.      }
  754.      break;
  755.  
  756.       case 4:
  757.      val = InputIntegerValue( x0 + 42, y0 + 64, MapMinX, MapMaxX, Things[ obj->objnum].xpos);
  758.      if (val >= MapMinX)
  759.      {
  760.         n = val - Things[ obj->objnum].xpos;
  761.         for (cur = obj; cur; cur = cur->next)
  762.            Things[ cur->objnum].xpos += n;
  763.         MadeChanges = TRUE;
  764.      }
  765.      break;
  766.  
  767.       case 5:
  768.      val = InputIntegerValue( x0 + 42, y0 + 74, MapMinY, MapMaxY, Things[ obj->objnum].ypos);
  769.      if (val >= MapMinY)
  770.      {
  771.         n = val - Things[ obj->objnum].ypos;
  772.         for (cur = obj; cur; cur = cur->next)
  773.            Things[ cur->objnum].ypos += n;
  774.         MadeChanges = TRUE;
  775.      }
  776.      break;
  777.       }
  778.       break;
  779.  
  780.    case OBJ_VERTEXES:
  781.       for (n = 0; n < 3; n++)
  782.      menustr[ n] = GetMemory( 60);
  783.       sprintf( menustr[ 2], "Edit Vertex #%d", obj->objnum);
  784.       sprintf( menustr[ 0], "Change X position (Current: %d)", Vertexes[ obj->objnum].x);
  785.       sprintf( menustr[ 1], "Change Y position (Current: %d)", Vertexes[ obj->objnum].y);
  786.       val = DisplayMenuArray( 0, 30, menustr[ 2], 2, NULL, menustr, dummy);
  787.       for (n = 0; n < 3; n++)
  788.      FreeMemory( menustr[ n]);
  789.       switch (val)
  790.       {
  791.       case 1:
  792.      val = InputIntegerValue( x0 + 42, y0 + 34, min( MapMinX, -10000), max( MapMaxX, 10000), Vertexes[ obj->objnum].x);
  793.      if (val >= min( MapMinX, -10000))
  794.      {
  795.         n = val - Vertexes[ obj->objnum].x;
  796.         for (cur = obj; cur; cur = cur->next)
  797.            Vertexes[ cur->objnum].x += n;
  798.         MadeChanges = TRUE;
  799.         MadeMapChanges = TRUE;
  800.      }
  801.      break;
  802.  
  803.       case 2:
  804.      val = InputIntegerValue( x0 + 42, y0 + 44, min( MapMinY, -10000), max( MapMaxY, 10000), Vertexes[ obj->objnum].y);
  805.      if (val >= min( MapMinY, -10000))
  806.      {
  807.         n = val - Vertexes[ obj->objnum].y;
  808.         for (cur = obj; cur; cur = cur->next)
  809.            Vertexes[ cur->objnum].y += n;
  810.         MadeChanges = TRUE;
  811.         MadeMapChanges = TRUE;
  812.      }
  813.      break;
  814.       }
  815.       break;
  816.  
  817.    case OBJ_LINEDEFS:
  818.       switch (DisplayMenu( x0, y0, "Choose the object to edit:",
  819.                "Edit the LineDef",
  820.                (LineDefs[ obj->objnum].sidedef1 >= 0) ? "Edit the 1st SideDef" : "Add a 1st SideDef",
  821.                (LineDefs[ obj->objnum].sidedef2 >= 0) ? "Edit the 2nd SideDef" : "Add a 2nd SideDef",
  822.                NULL))
  823.       {
  824.       case 1:
  825.      for (n = 0; n < 8; n++)
  826.         menustr[ n] = GetMemory( 60);
  827.      sprintf( menustr[ 7], "Edit LineDef #%d", obj->objnum);
  828.      sprintf( menustr[ 0], "Change Flags            (Current: %d)", LineDefs[ obj->objnum].flags);
  829.      sprintf( menustr[ 1], "Change Type             (Current: %d)", LineDefs[ obj->objnum].type);
  830.      sprintf( menustr[ 2], "Change Sector tag       (Current: %d)", LineDefs[ obj->objnum].tag);
  831.      sprintf( menustr[ 3], "Change Starting Vertex  (Current: #%d)", LineDefs[ obj->objnum].start);
  832.      sprintf( menustr[ 4], "Change Ending Vertex    (Current: #%d)", LineDefs[ obj->objnum].end);
  833.      sprintf( menustr[ 5], "Change 1st SideDef ref. (Current: #%d)", LineDefs[ obj->objnum].sidedef1);
  834.      sprintf( menustr[ 6], "Change 2nd SideDef ref. (Current: #%d)", LineDefs[ obj->objnum].sidedef2);
  835.      val = DisplayMenuArray( x0 + 42, y0 + 34, menustr[ 7], 7, NULL, menustr, dummy);
  836.      for (n = 0; n < 8; n++)
  837.         FreeMemory( menustr[ n]);
  838.      switch (val)
  839.      {
  840.      case 1:
  841.         val = DisplayMenu( x0 + 84, y0 + 68, "Toggle the flags:",
  842.                    GetLineDefFlagsLongName( 0x01),
  843.                    GetLineDefFlagsLongName( 0x02),
  844.                    GetLineDefFlagsLongName( 0x04),
  845.                    GetLineDefFlagsLongName( 0x08),
  846.                    GetLineDefFlagsLongName( 0x10),
  847.                    GetLineDefFlagsLongName( 0x20),
  848.                    GetLineDefFlagsLongName( 0x40),
  849.                    GetLineDefFlagsLongName( 0x80),
  850.                    GetLineDefFlagsLongName( 0x100),
  851.                    "(Enter a decimal value)",
  852.                    NULL);
  853.         if (val >= 1 && val <= 9)
  854.         {
  855.            for (cur = obj; cur; cur = cur->next)
  856.           LineDefs[ cur->objnum].flags ^= 0x01 << (val - 1);
  857.            MadeChanges = TRUE;
  858.         }
  859.         else if (val == 10)
  860.         {
  861.            val = InputIntegerValue( x0 + 126, y0 + 182, 0, 511, LineDefs[ obj->objnum].flags);
  862.            if (val >= 0)
  863.            {
  864.           for (cur = obj; cur; cur = cur->next)
  865.              LineDefs[ cur->objnum].flags = val;
  866.           MadeChanges = TRUE;
  867.            }
  868.         }
  869.         break;
  870.      case 2:
  871.         switch (DisplayMenu( x0 + 84, y0 + 78, "Choose a LineDef type:",
  872.                  "Normal",
  873.                  "Doors...",
  874.                  "Ceilings...",
  875.                  "Floors...",
  876.                  "Lifts & Moving things...",
  877.                  "Special...",
  878.                  "(Enter a decimal value)",
  879.                  NULL))
  880.         {
  881.         case 1:
  882.            val = 0;
  883.            break;
  884.         case 2:
  885.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 122, NULL, /* Doors */
  886.                          1, 26, 27, 28, 63, 29, 90, 31, 32, 34, 33, 61, 103, 86, 2, 46, 42, 75, 3, 76, 16,
  887.                          -1);
  888.            break;
  889.         case 3:
  890.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 132, NULL, /* Ceilings */
  891.                          41, 44, 40,
  892.                          -1);
  893.            break;
  894.         case 4:
  895.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 142, NULL, /* Floors */
  896.                          102, 70, 23, 9, 21, 82, 19, 38, 37, 98, 36, 18, 20, 14, 5, 22, 59, 30, 58, 91, 56,
  897.                          -1);
  898.            break;
  899.         case 5:
  900.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 152, NULL, /* Lifts & Moving things */
  901.                          62, 88, 10, 77, 73, 74, 87, 89, 7, 8,
  902.                          -1);
  903.            break;
  904.         case 6:
  905.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 162, NULL, /* Special */
  906.                          48, 11, 52, 51, 97, 39, 13, 35, 80, 104,
  907.                          -1);
  908.            break;
  909.         case 7:
  910.            val = InputIntegerValue( x0 + 126, y0 + 172, 0, 255, LineDefs[ obj->objnum].type);
  911.            break;
  912.         default:
  913.            val = -1;
  914.         }
  915.         if (val >= 0)
  916.         {
  917.            for (cur = obj; cur; cur = cur->next)
  918.           LineDefs[ cur->objnum].type = val;
  919.            MadeChanges = TRUE;
  920.         }
  921.         break;
  922.      case 3:
  923.         val = InputIntegerValue( x0 + 84, y0 + 88, 0, 255, LineDefs[ obj->objnum].tag);
  924.         if (val >= 0)
  925.         {
  926.            for (cur = obj; cur; cur = cur->next)
  927.           LineDefs[ cur->objnum].tag = val;
  928.            MadeChanges = TRUE;
  929.         }
  930.         break;
  931.      case 4:
  932.         val = InputObjectXRef( x0 + 84, y0 + 98, OBJ_VERTEXES, FALSE, LineDefs[ obj->objnum].start);
  933.         if (val >= 0)
  934.         {
  935.            for (cur = obj; cur; cur = cur->next)
  936.           LineDefs[ cur->objnum].start = val;
  937.            MadeChanges = TRUE;
  938.            MadeMapChanges = TRUE;
  939.         }
  940.         break;
  941.      case 5:
  942.         val = InputObjectXRef( x0 + 84, y0 + 108, OBJ_VERTEXES, FALSE, LineDefs[ obj->objnum].end);
  943.         if (val >= 0)
  944.         {
  945.            for (cur = obj; cur; cur = cur->next)
  946.           LineDefs[ cur->objnum].end = val;
  947.            MadeChanges = TRUE;
  948.            MadeMapChanges = TRUE;
  949.         }
  950.         break;
  951.      case 6:
  952.         val = InputObjectXRef( x0 + 84, y0 + 118, OBJ_SIDEDEFS, TRUE, LineDefs[ obj->objnum].sidedef1);
  953.         if (val >= -1)
  954.         {
  955.            for (cur = obj; cur; cur = cur->next)
  956.           LineDefs[ cur->objnum].sidedef1 = val;
  957.            MadeChanges = TRUE;
  958.            MadeMapChanges = TRUE;
  959.         }
  960.         break;
  961.      case 7:
  962.         val = InputObjectXRef( x0 + 84, y0 + 128, OBJ_SIDEDEFS, TRUE, LineDefs[ obj->objnum].sidedef2);
  963.         if (val >= -1)
  964.         {
  965.            for (cur = obj; cur; cur = cur->next)
  966.           LineDefs[ cur->objnum].sidedef2 = val;
  967.            MadeChanges = TRUE;
  968.            MadeMapChanges = TRUE;
  969.         }
  970.         break;
  971.      }
  972.      break;
  973.  
  974.       /* edit or add the first SideDef */
  975.       case 2:
  976.      ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  977.      if (LineDefs[ obj->objnum].sidedef1 >= 0)
  978.      {
  979.         /* build a new selection list with the first SideDefs */
  980.         objtype = OBJ_SIDEDEFS;
  981.         sdlist = NULL;
  982.         for (cur = obj; cur; cur = cur->next)
  983.            if (LineDefs[ cur->objnum].sidedef1 >= 0)
  984.           SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef1);
  985.      }
  986.      else
  987.      {
  988.         /* add a new first SideDef */
  989.         for (cur = obj; cur; cur = cur->next)
  990.            if (LineDefs[ cur->objnum].sidedef1 == -1)
  991.            {
  992.           InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  993.           LineDefs[ cur->objnum].sidedef1 = NumSideDefs - 1;
  994.            }
  995.         break;
  996.      }
  997.      /* no break here */
  998.  
  999.       /* edit or add the second SideDef */
  1000.       case 3:
  1001.      if (objtype != OBJ_SIDEDEFS)
  1002.      {
  1003.         if (LineDefs[ obj->objnum].sidedef2 >= 0)
  1004.         {
  1005.            /* build a new selection list with the second (or first) SideDefs */
  1006.            objtype = OBJ_SIDEDEFS;
  1007.            sdlist = NULL;
  1008.            for (cur = obj; cur; cur = cur->next)
  1009.           if (LineDefs[ cur->objnum].sidedef2 >= 0)
  1010.              SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef2);
  1011.           else if (LineDefs[ cur->objnum].sidedef1 >= 0)
  1012.              SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef1);
  1013.         }
  1014.         else
  1015.         {
  1016.            /* add a new second (or first) SideDef */
  1017.            for (cur = obj; cur; cur = cur->next)
  1018.           if (LineDefs[ cur->objnum].sidedef1 == -1)
  1019.           {
  1020.              InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  1021.              ObjectsNeeded( OBJ_LINEDEFS, 0);
  1022.              LineDefs[ cur->objnum].sidedef1 = NumSideDefs - 1;
  1023.           }
  1024.           else if (LineDefs[ cur->objnum].sidedef2 == -1)
  1025.           {
  1026.              n = LineDefs[ cur->objnum].sidedef1;
  1027.              InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  1028.              strncpy( SideDefs[ NumSideDefs - 1].tex3, "-", 8);
  1029.              strncpy( SideDefs[ n].tex3, "-", 8);
  1030.              ObjectsNeeded( OBJ_LINEDEFS, 0);
  1031.              LineDefs[ cur->objnum].sidedef2 = NumSideDefs - 1;
  1032.              LineDefs[ cur->objnum].flags = 4;
  1033.           }
  1034.            break;
  1035.         }
  1036.      }
  1037.      ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1038.      for (n = 0; n < 7; n++)
  1039.         menustr[ n] = GetMemory( 60);
  1040.      sprintf( menustr[ 6], "Edit SideDef #%d", sdlist->objnum);
  1041.      texname[ 8] = '\0';
  1042.      strncpy( texname, SideDefs[ sdlist->objnum].tex3, 8);
  1043.      sprintf( menustr[ 0], "Change Normal Texture   (Current: %s)", texname);
  1044.      strncpy( texname, SideDefs[ sdlist->objnum].tex1, 8);
  1045.      sprintf( menustr[ 1], "Change Upper texture    (Current: %s)", texname);
  1046.      strncpy( texname, SideDefs[ sdlist->objnum].tex2, 8);
  1047.      sprintf( menustr[ 2], "Change Lower texture    (Current: %s)", texname);
  1048.      sprintf( menustr[ 3], "Change Texture X offset (Current: %d)", SideDefs[ sdlist->objnum].xoff);
  1049.      sprintf( menustr[ 4], "Change Texture Y offset (Current: %d)", SideDefs[ sdlist->objnum].yoff);
  1050.      sprintf( menustr[ 5], "Change Sector ref.      (Current: #%d)", SideDefs[ sdlist->objnum].sector);
  1051.      val = DisplayMenuArray( x0 + 42, y0 + 54, menustr[ 6], 6, NULL, menustr, dummy);
  1052.      for (n = 0; n < 7; n++)
  1053.         FreeMemory( menustr[ n]);
  1054.      switch (val)
  1055.      {
  1056.      case 1:
  1057.         strncpy( texname, SideDefs[ sdlist->objnum].tex3, 8);
  1058.         ObjectsNeeded( 0);
  1059.         ChooseWallTexture( x0 + 84, y0 + 88, "Choose a wall texture", NumWTexture, WTexture, texname);
  1060.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1061.         if (strlen(texname) > 0)
  1062.         {
  1063.            for (cur = sdlist; cur; cur = cur->next)
  1064.           if (cur->objnum >= 0)
  1065.              strncpy( SideDefs[ cur->objnum].tex3, texname, 8);
  1066.            MadeChanges = TRUE;
  1067.         }
  1068.         break;
  1069.      case 2:
  1070.         strncpy( texname, SideDefs[ sdlist->objnum].tex1, 8);
  1071.         ObjectsNeeded( 0);
  1072.         ChooseWallTexture( x0 + 84, y0 + 98, "Choose a wall texture", NumWTexture, WTexture, texname);
  1073.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1074.         if (strlen(texname) > 0)
  1075.         {
  1076.            for (cur = sdlist; cur; cur = cur->next)
  1077.           if (cur->objnum >= 0)
  1078.              strncpy( SideDefs[ cur->objnum].tex1, texname, 8);
  1079.            MadeChanges = TRUE;
  1080.         }
  1081.         break;
  1082.      case 3:
  1083.         strncpy( texname, SideDefs[ sdlist->objnum].tex2, 8);
  1084.         ObjectsNeeded( 0);
  1085.         ChooseWallTexture( x0 + 84, y0 + 108, "Choose a wall texture", NumWTexture, WTexture, texname);
  1086.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1087.         if (strlen(texname) > 0)
  1088.         {
  1089.            for (cur = sdlist; cur; cur = cur->next)
  1090.           if (cur->objnum >= 0)
  1091.              strncpy( SideDefs[ cur->objnum].tex2, texname, 8);
  1092.            MadeChanges = TRUE;
  1093.         }
  1094.         break;
  1095.      case 4:
  1096.         val = InputIntegerValue( x0 + 84, y0 + 118, -255, 255, SideDefs[ sdlist->objnum].xoff);
  1097.         if (val >= -255)
  1098.         {
  1099.            for (cur = sdlist; cur; cur = cur->next)
  1100.           if (cur->objnum >= 0)
  1101.              SideDefs[ cur->objnum].xoff = val;
  1102.            MadeChanges = TRUE;
  1103.         }
  1104.         break;
  1105.      case 5:
  1106.         val = InputIntegerValue( x0 + 84, y0 + 128, -255, 255, SideDefs[ sdlist->objnum].yoff);
  1107.         if (val >= -255)
  1108.         {
  1109.            for (cur = sdlist; cur; cur = cur->next)
  1110.           if (cur->objnum >= 0)
  1111.              SideDefs[ cur->objnum].yoff = val;
  1112.            MadeChanges = TRUE;
  1113.         }
  1114.         break;
  1115.      case 6:
  1116.         val = InputObjectXRef( x0 + 84, y0 + 138, OBJ_SECTORS, FALSE, SideDefs[ sdlist->objnum].sector);
  1117.         if (val >= 0)
  1118.         {
  1119.            for (cur = sdlist; cur; cur = cur->next)
  1120.           if (cur->objnum >= 0)
  1121.              SideDefs[ cur->objnum].sector = val;
  1122.            MadeChanges = TRUE;
  1123.         }
  1124.         break;
  1125.      }
  1126.      ForgetSelection( &sdlist);
  1127.      break;
  1128.  
  1129.       }
  1130.       break;
  1131.  
  1132.    case OBJ_SECTORS:
  1133.       for (n = 0; n < 8; n++)
  1134.      menustr[ n] = GetMemory( 60);
  1135.       sprintf( menustr[ 7], "Edit Sector #%d", obj->objnum);
  1136.       sprintf( menustr[ 0], "Change Floor height     (Current: %d)", Sectors[ obj->objnum].floorh);
  1137.       sprintf( menustr[ 1], "Change Ceiling height   (Current: %d)", Sectors[ obj->objnum].ceilh);
  1138.       texname[ 8] = '\0';
  1139.       strncpy( texname, Sectors[ obj->objnum].floort, 8);
  1140.       sprintf( menustr[ 2], "Change Floor texture    (Current: %s)", texname);
  1141.       strncpy( texname, Sectors[ obj->objnum].ceilt, 8);
  1142.       sprintf( menustr[ 3], "Change Ceiling texture  (Current: %s)", texname);
  1143.       sprintf( menustr[ 4], "Change Light level      (Current: %d)", Sectors[ obj->objnum].light);
  1144.       sprintf( menustr[ 5], "Change Type             (Current: %d)", Sectors[ obj->objnum].special);
  1145.       sprintf( menustr[ 6], "Change LineDef tag      (Current: %d)", Sectors[ obj->objnum].tag);
  1146.       val = DisplayMenuArray( x0, y0, menustr[ 7], 7, NULL, menustr, dummy);
  1147.       for (n = 0; n < 8; n++)
  1148.      FreeMemory( menustr[ n]);
  1149.       switch (val)
  1150.       {
  1151.       case 1:
  1152.      val = InputIntegerValue( x0 + 42, y0 + 34, -512, 511, Sectors[ obj->objnum].floorh);
  1153.      if (val >= -512)
  1154.      {
  1155.         for (cur = obj; cur; cur = cur->next)
  1156.            Sectors[ cur->objnum].floorh = val;
  1157.         MadeChanges = TRUE;
  1158.      }
  1159.      break;
  1160.       case 2:
  1161.      val = InputIntegerValue( x0 + 42, y0 + 44, -512, 511, Sectors[ obj->objnum].ceilh);
  1162.      if (val >= -512)
  1163.      {
  1164.         for (cur = obj; cur; cur = cur->next)
  1165.            Sectors[ cur->objnum].ceilh = val;
  1166.         MadeChanges = TRUE;
  1167.      }
  1168.      break;
  1169.       case 3:
  1170.      strncpy( texname, Sectors[ obj->objnum].floort, 8);
  1171.      ObjectsNeeded( 0);
  1172.      ChooseFloorTexture( x0 + 42, y0 + 54, "Choose a floor texture", NumFTexture, FTexture, texname);
  1173.      ObjectsNeeded( OBJ_SECTORS, 0);
  1174.      if (strlen(texname) > 0)
  1175.      {
  1176.         for (cur = obj; cur; cur = cur->next)
  1177.            strncpy( Sectors[ cur->objnum].floort, texname, 8);
  1178.         MadeChanges = TRUE;
  1179.      }
  1180.      break;
  1181.       case 4:
  1182.      strncpy( texname, Sectors[ obj->objnum].ceilt, 8);
  1183.      ObjectsNeeded( 0);
  1184.      ChooseFloorTexture( x0 + 42, y0 + 64, "Choose a ceiling texture", NumFTexture, FTexture, texname);
  1185.      ObjectsNeeded( OBJ_SECTORS, 0);
  1186.      if (strlen(texname) > 0)
  1187.      {
  1188.         for (cur = obj; cur; cur = cur->next)
  1189.            strncpy( Sectors[ cur->objnum].ceilt, texname, 8);
  1190.         MadeChanges = TRUE;
  1191.      }
  1192.      break;
  1193.       case 5:
  1194.      val = InputIntegerValue( x0 + 42, y0 + 74, 0, 255, Sectors[ obj->objnum].light);
  1195.      if (val >= 0)
  1196.      {
  1197.         for (cur = obj; cur; cur = cur->next)
  1198.            Sectors[ cur->objnum].light = val;
  1199.         MadeChanges = TRUE;
  1200.      }
  1201.      break;
  1202.       case 6:
  1203.      val = DisplayMenu( x0 + 42, y0 + 84, "Choose a special behaviour",
  1204.                 GetSectorTypeLongName( 0),
  1205.                 GetSectorTypeLongName( 1),
  1206.                 GetSectorTypeLongName( 2),
  1207.                 GetSectorTypeLongName( 3),
  1208.                 GetSectorTypeLongName( 4),
  1209.                 GetSectorTypeLongName( 5),
  1210.                 GetSectorTypeLongName( 7),
  1211.                 GetSectorTypeLongName( 8),
  1212.                 GetSectorTypeLongName( 9),
  1213.                 GetSectorTypeLongName( 10),
  1214.                 GetSectorTypeLongName( 11),
  1215.                 GetSectorTypeLongName( 12),
  1216.                 GetSectorTypeLongName( 13),
  1217.                 GetSectorTypeLongName( 14),
  1218.                 GetSectorTypeLongName( 16),
  1219.                 "(Enter a decimal value)",
  1220.                 NULL);
  1221.      switch (val)
  1222.      {
  1223.      case 1:
  1224.      case 2:
  1225.      case 3:
  1226.      case 4:
  1227.      case 5:
  1228.      case 6:
  1229.         for (cur = obj; cur; cur = cur->next)
  1230.            Sectors[ cur->objnum].special = val - 1;
  1231.         MadeChanges = TRUE;
  1232.         break;
  1233.      case 7:
  1234.      case 8:
  1235.      case 9:
  1236.      case 10:
  1237.      case 11:
  1238.      case 12:
  1239.      case 13:
  1240.      case 14:
  1241.         for (cur = obj; cur; cur = cur->next)
  1242.            Sectors[ cur->objnum].special = val;
  1243.         MadeChanges = TRUE;
  1244.         break;
  1245.      case 15:
  1246.         for (cur = obj; cur; cur = cur->next)
  1247.            Sectors[ cur->objnum].special = 16;
  1248.         MadeChanges = TRUE;
  1249.         break;
  1250.      case 16:
  1251.         val = InputIntegerValue( x0 + 84, y0 + 208, 0, 255, Sectors[ obj->objnum].special);
  1252.         if (val >= 0)
  1253.         {
  1254.            for (cur = obj; cur; cur = cur->next)
  1255.           Sectors[ cur->objnum].special = val;
  1256.            MadeChanges = TRUE;
  1257.         }
  1258.         break;
  1259.      }
  1260.      break;
  1261.       case 7:
  1262.      val = InputIntegerValue( x0 + 42, y0 + 94, 0, 999, Sectors[ obj->objnum].tag);
  1263.      if (val >= 0)
  1264.      {
  1265.         for (cur = obj; cur; cur = cur->next)
  1266.            Sectors[ cur->objnum].tag = val;
  1267.         MadeChanges = TRUE;
  1268.      }
  1269.      break;
  1270.       }
  1271.       break;
  1272.    }
  1273. }
  1274.  
  1275.  
  1276.  
  1277. /*
  1278.    Yuck!  Dirty piece of code...
  1279. */
  1280.  
  1281. Bool Input2Numbers( int x0, int y0, char *name1, char *name2, int v1max, int v2max, int *v1, int *v2)
  1282. {
  1283.    int  val, key;
  1284.    int  maxlen, first;
  1285.    Bool ok;
  1286.    char prompt[ 80];
  1287.  
  1288.    if (UseMouse)
  1289.       HideMousePointer();
  1290.    sprintf( prompt, "Give the %s and %s for the object:", name1, name2);
  1291.    maxlen = strlen( prompt);
  1292.    if (x0 < 0)
  1293.       x0 = (ScrMaxX - 25 - 8 * maxlen) / 2;
  1294.    if (y0 < 0)
  1295.       y0 = (ScrMaxY - 75) / 2;
  1296.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * maxlen, y0 + 75);
  1297.    DrawScreenText( x0 + 10, y0 + 26, name1);
  1298.    DrawScreenText( x0 + 180, y0 + 26, name2);
  1299.    DrawScreenText( x0 + 10, y0 + 58, "(0-%d)", v1max);
  1300.    DrawScreenText( x0 + 180, y0 + 58, "(0-%d)", v2max);
  1301.    SetColor( WHITE);
  1302.    DrawScreenText( x0 + 10, y0 + 8, prompt);
  1303.    first = TRUE;
  1304.    key = 0;
  1305.    for (;;)
  1306.    {
  1307.       ok = TRUE;
  1308.       DrawScreenBox3D( x0 + 10, y0 + 38, x0 + 71, y0 + 51);
  1309.       if (*v1 < 0 || *v1 > v1max)
  1310.       {
  1311.      SetColor( DARKGRAY);
  1312.      ok = FALSE;
  1313.       }
  1314.       DrawScreenText( x0 + 14, y0 + 41, "%d", *v1);
  1315.       DrawScreenBox3D( x0 + 180, y0 + 38, x0 + 241, y0 + 51);
  1316.       if (*v2 < 0 || *v2 > v2max)
  1317.       {
  1318.      SetColor( DARKGRAY);
  1319.      ok = FALSE;
  1320.       }
  1321.       DrawScreenText( x0 + 184, y0 + 41, "%d", *v2);
  1322.       if (first)
  1323.      key = InputInteger( x0 + 10, y0 + 38, v1, 0, v1max);
  1324.       else
  1325.      key = InputInteger( x0 + 180, y0 + 38, v2, 0, v2max);
  1326.       if ((key & 0xFF00) == 0x4B00 || (key & 0xFF00) == 0x4D00 || (key & 0x00FF) == 0x0009 || (key & 0xFF00) == 0x0F00)
  1327.      first = !first;
  1328.       else if ((key & 0x00FF) == 0x001B)
  1329.      break;
  1330.       else if ((key & 0x00FF) == 0x000D)
  1331.       {
  1332.      if (first)
  1333.         first = FALSE;
  1334.      else if (ok)
  1335.         break;
  1336.      else
  1337.         Beep();
  1338.       }
  1339.       else
  1340.      Beep();
  1341.    }
  1342.    if (UseMouse)
  1343.       ShowMousePointer();
  1344.    return ((key & 0x00FF) == 0x000D);
  1345. }
  1346.  
  1347.  
  1348.  
  1349. /*
  1350.    display number of objects, etc.
  1351. */
  1352.  
  1353. void Statistics( int x0, int y0)
  1354. {
  1355.    if (x0 < 0)
  1356.       x0 = (ScrMaxX - 270) / 2;
  1357.    if (y0 < 0)
  1358.       y0 = (ScrMaxY - 100) / 2;
  1359.    if (UseMouse)
  1360.       HideMousePointer();
  1361.    DrawScreenBox3D( x0, y0, x0 + 270, y0 + 100);
  1362.    SetColor( WHITE);
  1363.    DrawScreenText( x0 + 10, y0 + 5, "Statistics");
  1364.    if (Things == NULL)
  1365.       SetColor( DARKGRAY);
  1366.    else
  1367.       SetColor( BLACK);
  1368.    DrawScreenText( -1, y0 + 25, "Number of Things:   %4d (%lu K)",
  1369.            NumThings, ((unsigned long) NumThings * sizeof( struct Thing) + 512L) / 1024L);
  1370.    if (Vertexes == NULL)
  1371.       SetColor( DARKGRAY);
  1372.    else
  1373.       SetColor( BLACK);
  1374.    DrawScreenText( -1, -1, "Number of Vertices: %4d (%lu K)",
  1375.            NumVertexes, ((unsigned long) NumVertexes * sizeof( struct Vertex) + 512L) / 1024L);
  1376.    if (LineDefs == NULL)
  1377.       SetColor( DARKGRAY);
  1378.    else
  1379.       SetColor( BLACK);
  1380.    DrawScreenText( -1, -1, "Number of LineDefs: %4d (%lu K)",
  1381.            NumLineDefs, ((unsigned long) NumLineDefs * sizeof( struct LineDef) + 512L) / 1024L);
  1382.    if (SideDefs == NULL)
  1383.       SetColor( DARKGRAY);
  1384.    else
  1385.       SetColor( BLACK);
  1386.    DrawScreenText( -1, -1, "Number of SideDefs: %4d (%lu K)",
  1387.            NumSideDefs, ((unsigned long) NumSideDefs * sizeof( struct SideDef) + 512L) / 1024L);
  1388.    if (Sectors == NULL)
  1389.       SetColor( DARKGRAY);
  1390.    else
  1391.       SetColor( BLACK);
  1392.    DrawScreenText( -1, -1, "Number of Sectors:  %4d (%lu K)",
  1393.            NumSectors, ((unsigned long) NumSectors * sizeof( struct Sector) + 512L) / 1024L);
  1394.    SetColor( YELLOW);
  1395.    DrawScreenText( x0 + 10, y0 + 85, "Press any key to continue...");
  1396.    bioskey( 0);
  1397.    if (UseMouse)
  1398.       ShowMousePointer();
  1399. }
  1400.  
  1401.  
  1402. /*
  1403.    display a message, then ask if the check should continue (prompt2 may be NULL)
  1404. */
  1405.  
  1406. Bool CheckFailed( int x0, int y0, char *prompt1, char *prompt2, Bool fatal)
  1407. {
  1408.    int key;
  1409.    int maxlen;
  1410.  
  1411.    if (UseMouse)
  1412.       HideMousePointer();
  1413.    if (fatal == TRUE)
  1414.       maxlen = 44;
  1415.    else
  1416.       maxlen = 27;
  1417.    if (strlen( prompt1) > maxlen)
  1418.       maxlen = strlen( prompt1);
  1419.    if (prompt2 != NULL && strlen( prompt2) > maxlen)
  1420.       maxlen = strlen( prompt2);
  1421.    if (x0 < 0)
  1422.       x0 = (ScrMaxX - 22 - 8 * maxlen) / 2;
  1423.    if (y0 < 0)
  1424.       y0 = (ScrMaxY - (prompt2 ? 63 : 53) - (fatal ? 10 : 0)) / 2;
  1425.    DrawScreenBox3D( x0, y0, x0 + 22 + 8 * maxlen, y0 + (prompt2 ? 63 : 53) + (fatal ? 10 : 0));
  1426.    SetColor( RED);
  1427.    DrawScreenText( x0 + 10, y0 + 8, "Verification failed:");
  1428.    Beep();
  1429.    SetColor( WHITE);
  1430.    DrawScreenText( x0 + 10, y0 + 18, prompt1);
  1431.    LogMessage( "\t%s\n", prompt1);
  1432.    if (prompt2 != NULL)
  1433.    {
  1434.       DrawScreenText( x0 + 10, y0 + 28, prompt2);
  1435.       LogMessage( "\t%s\n", prompt2);
  1436.    }
  1437.    if (fatal == TRUE)
  1438.    {
  1439.       DrawScreenText( x0 + 10, y0 + (prompt2 ? 38 : 28), "DOOM will crash if you play with this level.");
  1440.       SetColor( YELLOW);
  1441.       DrawScreenText( x0 + 10, y0 + (prompt2 ? 58 : 48), "Press any key to see the object");
  1442.       LogMessage( "\n");
  1443.    }
  1444.    else
  1445.    {
  1446.       SetColor( YELLOW);
  1447.       DrawScreenText( x0 + 10, y0 + (prompt2 ? 48 : 38), "Press Esc to see the object");
  1448.    }
  1449.    key = bioskey( 0);
  1450.    if ((key & 0x00FF) != 0x001B)
  1451.    {
  1452.       DrawScreenBox3D( x0, y0, x0 + 22 + 8 * maxlen, y0 + (prompt2 ? 63 : 53) + (fatal ? 10 : 0));
  1453.       DrawScreenText( x0 + 10, y0 + 28, "Verifying other objects...");
  1454.    }
  1455.    if (UseMouse)
  1456.       ShowMousePointer();
  1457.    return ((key & 0x00FF) == 0x001B);
  1458. }
  1459.  
  1460.  
  1461.  
  1462.  
  1463. /*
  1464.    check if all sectors are closed
  1465. */
  1466.  
  1467. void CheckSectors() /* SWAP! */
  1468. {
  1469.    int        s, n, sd;
  1470.    char huge *ends;
  1471.    char       msg1[ 80], msg2[80];
  1472.  
  1473.    LogMessage( "\nVerifying Sectors...\n");
  1474.    ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1475.    ends = GetFarMemory( NumVertexes * sizeof( char));
  1476.    for (s = 0; s < NumSectors; s++)
  1477.    {
  1478.       /* clear the "ends" array */
  1479.       for (n = 0; n < NumVertexes; n++)
  1480.      ends[ n] = 0;
  1481.       /* for each SideDef bound to the Sector, store a "1" in the "ends" */
  1482.       /* array for its starting Vertex, and a "2" for its ending Vertex  */
  1483.       for (n = 0; n < NumLineDefs; n++)
  1484.       {
  1485.      sd = LineDefs[ n].sidedef1;
  1486.      if (sd >= 0 && SideDefs[ sd].sector == s)
  1487.      {
  1488.         ends[ LineDefs[ n].start] |= 1;
  1489.         ends[ LineDefs[ n].end] |= 2;
  1490.      }
  1491.      sd = LineDefs[ n].sidedef2;
  1492.      if (sd >= 0 && SideDefs[ sd].sector == s)
  1493.      {
  1494.         ends[ LineDefs[ n].end] |= 1;
  1495.         ends[ LineDefs[ n].start] |= 2;
  1496.      }
  1497.       }
  1498.       /* every entry in the "ends" array should be "0" or "3" */
  1499.       for (n = 0; n < NumVertexes; n++)
  1500.       {
  1501.      if (ends[ n] == 1)
  1502.      {
  1503.         sprintf( msg1, "Sector #%d is not closed!", s);
  1504.         sprintf( msg2, "There is no SideDef ending at Vertex #%d", n);
  1505.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1506.         {
  1507.            GoToObject( OBJ_VERTEXES, n);
  1508.            return;
  1509.         }
  1510.      }
  1511.      if (ends[ n] == 2)
  1512.      {
  1513.         sprintf( msg1, "Sector #%d is not closed!", s);
  1514.         sprintf( msg2, "There is no SideDef starting at Vertex #%d", n);
  1515.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1516.         {
  1517.            GoToObject( OBJ_VERTEXES, n);
  1518.            return;
  1519.         }
  1520.      }
  1521.       }
  1522.    }
  1523.    FreeFarMemory( ends);
  1524. }
  1525.  
  1526.  
  1527.  
  1528. /*
  1529.    check cross-references and delete unused objects
  1530. */
  1531.  
  1532. void CheckCrossReferences() /* SWAP! */
  1533. {
  1534.    char   msg[ 80];
  1535.    int    n, m;
  1536.    SelPtr cur;
  1537.  
  1538.    LogMessage( "\nVerifying cross-references...\n");
  1539.    ObjectsNeeded( OBJ_LINEDEFS, 0);
  1540.    for (n = 0; n < NumLineDefs; n++)
  1541.    {
  1542.       /* check for missing first SideDefs */
  1543.       if (LineDefs[ n].sidedef1 < 0)
  1544.       {
  1545.      sprintf( msg, "ERROR: LineDef #%d has no first SideDef!", n);
  1546.      CheckFailed( -1, -1, msg, NULL, TRUE);
  1547.      GoToObject( OBJ_LINEDEFS, n);
  1548.      return;
  1549.       }
  1550.       /* check for SideDefs used twice in the same LineDef */
  1551.       if (LineDefs[ n].sidedef1 == LineDefs[ n].sidedef2)
  1552.       {
  1553.      sprintf( msg, "ERROR: LineDef #%d uses the same SideDef twice (#%d)", n, LineDefs[ n].sidedef1);
  1554.      CheckFailed( -1, -1, msg, NULL, TRUE);
  1555.      GoToObject( OBJ_LINEDEFS, n);
  1556.      return;
  1557.       }
  1558.       /* check for Vertices used twice in the same LineDef */
  1559.       if (LineDefs[ n].start == LineDefs[ n].end)
  1560.       {
  1561.      sprintf( msg, "ERROR: LineDef #%d uses the same Vertex twice (#%d)", n, LineDefs[ n].start);
  1562.      CheckFailed( -1, -1, msg, NULL, TRUE);
  1563.      GoToObject( OBJ_LINEDEFS, n);
  1564.      return;
  1565.       }
  1566.    }
  1567.  
  1568.    /* check if there aren't two LineDefs between the same Vertices */
  1569.    cur = NULL;
  1570.    for (n = NumLineDefs - 1; n >= 1; n--)
  1571.    {
  1572.       for (m = n - 1; m >= 0; m--)
  1573.      if ((LineDefs[ n].start == LineDefs[ m].start && LineDefs[ n].end == LineDefs[ m].end)
  1574.       || (LineDefs[ n].start == LineDefs[ m].end && LineDefs[ n].end == LineDefs[ m].start))
  1575.      {
  1576.         SelectObject( &cur, n);
  1577.         break;
  1578.      }
  1579.    }
  1580.    if (cur && (Expert || Confirm(-1, -1, "There are multiple LineDefs between the same Vertices", "Do you want to delete the redundant LineDefs?")))
  1581.       DeleteObjects( OBJ_LINEDEFS, &cur);
  1582.    else
  1583.       ForgetSelection( &cur);
  1584.  
  1585.    /* check for invalid flags in the LineDefs */
  1586.    for (n = 0; n < NumLineDefs; n++)
  1587.       if ((LineDefs[ n].flags & 0x01) == 0 && LineDefs[ n].sidedef2 < 0)
  1588.      SelectObject( &cur, n);
  1589.    if (cur && (Expert || Confirm(-1, -1, "Some LineDefs have only one side but their Im bit is not set", "Do you want to set the 'Impassible' flag?")))
  1590.    {
  1591.       while (cur)
  1592.       {
  1593.      LineDefs[ cur->objnum].flags |= 0x01;
  1594.      UnSelectObject( &cur, cur->objnum);
  1595.       }
  1596.    }
  1597.    else
  1598.       ForgetSelection( &cur);
  1599.    for (n = 0; n < NumLineDefs; n++)
  1600.       if ((LineDefs[ n].flags & 0x04) != 0 && LineDefs[ n].sidedef2 < 0)
  1601.      SelectObject( &cur, n);
  1602.    if (cur && (Expert || Confirm(-1, -1, "Some LineDefs have only one side but their 2S bit is set", "Do you want to clear the 'two-sided' flag?")))
  1603.    {
  1604.       while (cur)
  1605.       {
  1606.      LineDefs[ cur->objnum].flags &= ~0x04;
  1607.      UnSelectObject( &cur, cur->objnum);
  1608.       }
  1609.    }
  1610.    else
  1611.       ForgetSelection( &cur);
  1612.    for (n = 0; n < NumLineDefs; n++)
  1613.       if ((LineDefs[ n].flags & 0x04) == 0 && LineDefs[ n].sidedef2 >= 0)
  1614.      SelectObject( &cur, n);
  1615.    if (cur && (Expert || Confirm(-1, -1, "Some LineDefs have two sides but their 2S bit is not set", "Do you want to set the 'two-sided' flag?")))
  1616.    {
  1617.       while (cur)
  1618.       {
  1619.      LineDefs[ cur->objnum].flags |= 0x04;
  1620.      UnSelectObject( &cur, cur->objnum);
  1621.       }
  1622.    }
  1623.    else
  1624.       ForgetSelection( &cur);
  1625.  
  1626.    /* select all Vertices */
  1627.    for (n = 0; n < NumVertexes; n++)
  1628.       SelectObject( &cur, n);
  1629.    /* unselect Vertices used in a LineDef */
  1630.    for (n = 0; n < NumLineDefs; n++)
  1631.    {
  1632.       m = LineDefs[ n].start;
  1633.       if (cur && m >= 0)
  1634.      UnSelectObject( &cur, m);
  1635.       m = LineDefs[ n].end;
  1636.       if (cur && m >= 0)
  1637.      UnSelectObject( &cur, m);
  1638.       continue;
  1639.    }
  1640.    /* check if there are any Vertices left */
  1641.    if (cur && (Expert || Confirm(-1, -1, "Some Vertices are not bound to any LineDef", "Do you want to delete these unused Vertices?")))
  1642.    {
  1643.       DeleteObjects( OBJ_VERTEXES, &cur);
  1644.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1645.    }
  1646.    else
  1647.       ForgetSelection( &cur);
  1648.  
  1649.    /* select all SideDefs */
  1650.    for (n = 0; n < NumSideDefs; n++)
  1651.       SelectObject( &cur, n);
  1652.    /* unselect SideDefs bound to a LineDef */
  1653.    for (n = 0; n < NumLineDefs; n++)
  1654.    {
  1655.       m = LineDefs[ n].sidedef1;
  1656.       if (cur && m >= 0)
  1657.      UnSelectObject( &cur, m);
  1658.       m = LineDefs[ n].sidedef2;
  1659.       if (cur && m >= 0)
  1660.      UnSelectObject( &cur, m);
  1661.       continue;
  1662.    }
  1663.    /* check if there are any SideDefs left */
  1664.    if (cur && (Expert || Confirm(-1, -1, "Some SideDefs are not bound to any LineDef", "Do you want to delete these unused SideDefs?")))
  1665.       DeleteObjects( OBJ_SIDEDEFS, &cur);
  1666.    else
  1667.       ForgetSelection( &cur);
  1668.  
  1669.    /* select all Sectors */
  1670.    for (n = 0; n < NumSectors; n++)
  1671.       SelectObject( &cur, n);
  1672.    /* unselect Sectors bound to a SideDef */
  1673.    for (n = 0; n < NumLineDefs; n++)
  1674.    {
  1675.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1676.       m = LineDefs[ n].sidedef1;
  1677.       ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1678.       if (cur && m >= 0 && SideDefs[ m].sector >= 0)
  1679.      UnSelectObject( &cur, SideDefs[ m].sector);
  1680.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1681.       m = LineDefs[ n].sidedef2;
  1682.       ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1683.       if (cur && m >= 0 && SideDefs[ m].sector >= 0)
  1684.      UnSelectObject( &cur, SideDefs[ m].sector);
  1685.       continue;
  1686.    }
  1687.    /* check if there are any Sectors left */
  1688.    if (cur && (Expert || Confirm(-1, -1, "Some Sectors are not bound to any SideDef", "Do you want to delete these unused Sectors?")))
  1689.       DeleteObjects( OBJ_SECTORS, &cur);
  1690.    else
  1691.       ForgetSelection( &cur);
  1692. }
  1693.  
  1694.  
  1695.  
  1696. /*
  1697.    check for missing textures
  1698. */
  1699.  
  1700. void CheckTextures() /* SWAP! */
  1701. {
  1702.    int  n;
  1703.    int  sd1, sd2;
  1704.    int  s1, s2;
  1705.    char msg1[ 80], msg2[ 80];
  1706.  
  1707.    LogMessage( "\nVerifying textures...\n");
  1708.    ObjectsNeeded( OBJ_SECTORS, 0);
  1709.    for (n = 0; n < NumSectors; n++)
  1710.    {
  1711.       if (Sectors[ n].ceilt[ 0] == '-' && Sectors[ n].ceilt == '\0')
  1712.       {
  1713.      sprintf( msg1, "Error: Sector #%d has no ceiling texture", n);
  1714.      sprintf( msg2, "You probaly used a brain-damaged editor to do that...");
  1715.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1716.      {
  1717.         GoToObject( OBJ_SECTORS, n);
  1718.         return;
  1719.      }
  1720.       }
  1721.       if (Sectors[ n].floort[ 0] == '-' && Sectors[ n].floort == '\0')
  1722.       {
  1723.      sprintf( msg1, "Error: Sector #%d has no floor texture", n);
  1724.      sprintf( msg2, "You probaly used a brain-damaged editor to do that...");
  1725.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1726.      {
  1727.         GoToObject( OBJ_SECTORS, n);
  1728.         return;
  1729.      }
  1730.       }
  1731.       if (Sectors[ n].ceilh < Sectors[ n].floorh)
  1732.       {
  1733.      sprintf( msg1, "Error: Sector #%d has its ceiling lower than its floor", n);
  1734.      sprintf( msg2, "The textures will never be displayed if you cannot go there");
  1735.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1736.      {
  1737.         GoToObject( OBJ_SECTORS, n);
  1738.         return;
  1739.      }
  1740.       }
  1741.    }
  1742.    for (n = 0; n < NumLineDefs; n++)
  1743.    {
  1744.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1745.       sd1 = LineDefs[ n].sidedef1;
  1746.       sd2 = LineDefs[ n].sidedef2;
  1747.       ObjectsNeeded( OBJ_SIDEDEFS, OBJ_SECTORS, 0);
  1748.       if (sd1 >= 0)
  1749.      s1 = SideDefs[ sd1].sector;
  1750.       else
  1751.      s1 = -1;
  1752.       if (sd2 >= 0)
  1753.      s2 = SideDefs[ sd2].sector;
  1754.       else
  1755.      s2 = -1;
  1756.       if (s1 >= 0 && s2 < 0)
  1757.       {
  1758.      if (SideDefs[ sd1].tex3[ 0] == '-' && SideDefs[ sd1].tex3[ 1] == '\0')
  1759.      {
  1760.         sprintf( msg1, "Error in one-sided Linedef #%d:", n);
  1761.         sprintf( msg2, "SideDef #%d has no normal texture", sd1);
  1762.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1763.         {
  1764.            GoToObject( OBJ_LINEDEFS, n);
  1765.            return;
  1766.         }
  1767.      }
  1768.       }
  1769.       if (s1 >= 0 && s2 >= 0 && Sectors[ s1].ceilh > Sectors[ s2].ceilh)
  1770.       {
  1771.      if (SideDefs[ sd1].tex1[ 0] == '-' && SideDefs[ sd1].tex1[ 1] == '\0'
  1772.          && strncmp( Sectors[ s1].ceilt, "F_SKY1", 8) && strncmp( Sectors[ s2].ceilt, "F_SKY1", 8))
  1773.      {
  1774.         sprintf( msg1, "Error in first SideDef of Linedef #%d:", n);
  1775.         sprintf( msg2, "SideDef #%d has no upper texture", sd1);
  1776.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1777.         {
  1778.            GoToObject( OBJ_LINEDEFS, n);
  1779.            return;
  1780.         }
  1781.      }
  1782.       }
  1783.       if (s1 >= 0 && s2 >= 0 && Sectors[ s1].floorh < Sectors[ s2].floorh)
  1784.       {
  1785.      if (SideDefs[ sd1].tex2[ 0] == '-' && SideDefs[ sd1].tex2[ 1] == '\0')
  1786.      {
  1787.         sprintf( msg1, "Error in first SideDef of Linedef #%d:", n);
  1788.         sprintf( msg2, "SideDef #%d has no lower texture", sd1);
  1789.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1790.         {
  1791.            GoToObject( OBJ_LINEDEFS, n);
  1792.            return;
  1793.         }
  1794.      }
  1795.       }
  1796.       if (s1 >= 0 && s2 >= 0 && Sectors[ s2].ceilh > Sectors[ s1].ceilh)
  1797.       {
  1798.      if (SideDefs[ sd2].tex1[ 0] == '-' && SideDefs[ sd2].tex1[ 1] == '\0'
  1799.          && strncmp( Sectors[ s1].ceilt, "F_SKY1", 8) && strncmp( Sectors[ s2].ceilt, "F_SKY1", 8))
  1800.      {
  1801.         sprintf( msg1, "Error in second SideDef of Linedef #%d:", n);
  1802.         sprintf( msg2, "SideDef #%d has no upper texture", sd2);
  1803.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1804.         {
  1805.            GoToObject( OBJ_LINEDEFS, n);
  1806.            return;
  1807.         }
  1808.      }
  1809.       }
  1810.       if (s1 >= 0 && s2 >= 0 && Sectors[ s2].floorh < Sectors[ s1].floorh)
  1811.       {
  1812.      if (SideDefs[ sd2].tex2[ 0] == '-' && SideDefs[ sd2].tex2[ 1] == '\0')
  1813.      {
  1814.         sprintf( msg1, "Error in second SideDef of Linedef #%d:", n);
  1815.         sprintf( msg2, "SideDef #%d has no lower texture", sd2);
  1816.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1817.         {
  1818.            GoToObject( OBJ_LINEDEFS, n);
  1819.            return;
  1820.         }
  1821.      }
  1822.       }
  1823.    }
  1824. }
  1825.  
  1826.  
  1827.  
  1828. /*
  1829.    check if a texture name matches one of the elements of a list
  1830. */
  1831.  
  1832. Bool IsTextureNameInList( char *name, char **list, int numelems)
  1833. {
  1834.    int n;
  1835.  
  1836.    for (n = 0; n < numelems; n++)
  1837.       if (! strnicmp( name, list[ n], 8))
  1838.      return TRUE;
  1839.    return FALSE;
  1840. }
  1841.  
  1842.  
  1843.  
  1844. /*
  1845.    check for invalid texture names
  1846. */
  1847.  
  1848. void CheckTextureNames() /* SWAP! */
  1849. {
  1850.    int  n;
  1851.    char msg1[ 80], msg2[ 80];
  1852.  
  1853.    LogMessage( "\nVerifying texture names...\n");
  1854.    if (FindMasterDir( MasterDir, "F2_START") == NULL)
  1855.       NumThings--;
  1856.    ObjectsNeeded( OBJ_SECTORS, 0);
  1857.    for (n = 0; n < NumSectors; n++)
  1858.    {
  1859.       if (! IsTextureNameInList( Sectors[ n].ceilt, FTexture, NumFTexture))
  1860.       {
  1861.      sprintf( msg1, "Invalid ceiling texture in Sector #%d", n);
  1862.      sprintf( msg2, "The name \"%s\" is not a floor/ceiling texture", Sectors[ n].ceilt);
  1863.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1864.      {
  1865.         GoToObject( OBJ_SECTORS, n);
  1866.         return;
  1867.      }
  1868.       }
  1869.       if (! IsTextureNameInList( Sectors[ n].floort, FTexture, NumFTexture))
  1870.       {
  1871.      sprintf( msg1, "Invalid floor texture in Sector #%d", n);
  1872.      sprintf( msg2, "The name \"%s\" is not a floor/ceiling texture", Sectors[ n].floort);
  1873.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1874.      {
  1875.         GoToObject( OBJ_SECTORS, n);
  1876.         return;
  1877.      }
  1878.       }
  1879.    }
  1880.    ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1881.    for (n = 0; n < NumSideDefs; n++)
  1882.    {
  1883.       if (! IsTextureNameInList( SideDefs[ n].tex1, WTexture, NumWTexture))
  1884.       {
  1885.      sprintf( msg1, "Invalid upper texture in SideDef #%d", n);
  1886.      sprintf( msg2, "The name \"%s\" is not a wall texture", SideDefs[ n].tex1);
  1887.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1888.      {
  1889.         GoToObject( OBJ_SIDEDEFS, n);
  1890.         return;
  1891.      }
  1892.       }
  1893.       if (! IsTextureNameInList( SideDefs[ n].tex2, WTexture, NumWTexture))
  1894.       {
  1895.      sprintf( msg1, "Invalid lower texture in SideDef #%d", n);
  1896.      sprintf( msg2, "The name \"%s\" is not a wall texture", SideDefs[ n].tex2);
  1897.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1898.      {
  1899.         GoToObject( OBJ_SIDEDEFS, n);
  1900.         return;
  1901.      }
  1902.       }
  1903.       if (! IsTextureNameInList( SideDefs[ n].tex3, WTexture, NumWTexture))
  1904.       {
  1905.      sprintf( msg1, "Invalid normal texture in SideDef #%d", n);
  1906.      sprintf( msg2, "The name \"%s\" is not a wall texture", SideDefs[ n].tex3);
  1907.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1908.      {
  1909.         GoToObject( OBJ_SIDEDEFS, n);
  1910.         return;
  1911.      }
  1912.       }
  1913.    }
  1914. }
  1915.  
  1916.  
  1917.  
  1918. /*
  1919.    check the level consistency
  1920. */
  1921.  
  1922. void CheckLevel( int x0, int y0) /* SWAP! */
  1923. {
  1924.    char *line5 = NULL;
  1925.  
  1926.    if (Registered)
  1927.    {
  1928.       if (FindMasterDir( MasterDir, "TEXTURE2") == NULL)
  1929.      NumVertexes--;
  1930.       else
  1931.      line5 = "Check texture names";
  1932.    }
  1933.    switch (DisplayMenu( x0, y0, ((x0 == -1) ? "Check level consistency" : NULL),
  1934.             "Number of objects",
  1935.             "Check if all Sectors are closed",
  1936.             "Check all cross-references",
  1937.             "Check for missing textures",
  1938.             line5,
  1939.             NULL))
  1940.    {
  1941.    case 1:
  1942.       Statistics( -1, -1);
  1943.       break;
  1944.    case 2:
  1945.       CheckSectors();
  1946.       break;
  1947.    case 3:
  1948.       CheckCrossReferences();
  1949.       break;
  1950.    case 4:
  1951.       CheckTextures();
  1952.       break;
  1953.    case 5:
  1954.       CheckTextureNames();
  1955.       break;
  1956.    }
  1957. }
  1958.  
  1959.  
  1960.  
  1961. /*
  1962.    insert a standard object at given position
  1963. */
  1964.  
  1965. void InsertStandardObject( int x0, int y0, int xpos, int ypos) /* SWAP! */
  1966. {
  1967.    int sector;
  1968.    int choice, n;
  1969.    int a, b, h;
  1970.  
  1971.    /* show where the object will be inserted */
  1972.    if (UseMouse)
  1973.       HideMousePointer();
  1974.    DrawPointer( TRUE);
  1975.    if (UseMouse)
  1976.       ShowMousePointer();
  1977.    /* are we inside a Sector? */
  1978.    sector = GetCurObject( OBJ_SECTORS, xpos, ypos, xpos, ypos);
  1979.    if (sector >= 0)
  1980.       choice = DisplayMenu( x0, y0, ((x0 == -1) ? "Insert a pre-defined object (inside a Sector)" : NULL),
  1981.                 "Rectangle",
  1982.                 "Polygon (N sides)",
  1983.                 "Stairs",
  1984.                 "Hidden stairs",
  1985.                 NULL);
  1986.    else
  1987.       choice = DisplayMenu( x0, y0, ((x0 == -1) ? "Insert a pre-defined object (outside)" : NULL),
  1988.                 "Rectangle",
  1989.                 "Polygon (N sides)",
  1990.                 NULL);
  1991.    /* !!!! Should also check for overlapping objects (sectors) !!!! */
  1992.    switch (choice)
  1993.    {
  1994.    case 1:
  1995.       a = 256;
  1996.       b = 128;
  1997.       if (Input2Numbers( -1, -1, "Width", "Height", 2000, 2000, &a, &b))
  1998.       {
  1999.      if (a < 8)
  2000.         a = 8;
  2001.      if (b < 8)
  2002.         b = 8;
  2003.      xpos = xpos - a / 2;
  2004.      ypos = ypos - b / 2;
  2005.      InsertObject( OBJ_VERTEXES, -1, xpos, ypos);
  2006.      InsertObject( OBJ_VERTEXES, -1, xpos + a, ypos);
  2007.      InsertObject( OBJ_VERTEXES, -1, xpos + a, ypos + b);
  2008.      InsertObject( OBJ_VERTEXES, -1, xpos, ypos + b);
  2009.      if (sector < 0)
  2010.         InsertObject( OBJ_SECTORS, -1, 0, 0);
  2011.      for (n = 0; n < 4; n++)
  2012.      {
  2013.         InsertObject( OBJ_LINEDEFS, -1, 0, 0);
  2014.         LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs;
  2015.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2016.         if (sector >= 0)
  2017.            SideDefs[ NumSideDefs - 1].sector = sector;
  2018.      }
  2019.      ObjectsNeeded( OBJ_LINEDEFS, 0);
  2020.      if (sector >= 0)
  2021.      {
  2022.         LineDefs[ NumLineDefs - 4].start = NumVertexes - 4;
  2023.         LineDefs[ NumLineDefs - 4].end = NumVertexes - 3;
  2024.         LineDefs[ NumLineDefs - 3].start = NumVertexes - 3;
  2025.         LineDefs[ NumLineDefs - 3].end = NumVertexes - 2;
  2026.         LineDefs[ NumLineDefs - 2].start = NumVertexes - 2;
  2027.         LineDefs[ NumLineDefs - 2].end = NumVertexes - 1;
  2028.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 1;
  2029.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 4;
  2030.      }
  2031.      else
  2032.      {
  2033.         LineDefs[ NumLineDefs - 4].start = NumVertexes - 1;
  2034.         LineDefs[ NumLineDefs - 4].end = NumVertexes - 2;
  2035.         LineDefs[ NumLineDefs - 3].start = NumVertexes - 2;
  2036.         LineDefs[ NumLineDefs - 3].end = NumVertexes - 3;
  2037.         LineDefs[ NumLineDefs - 2].start = NumVertexes - 3;
  2038.         LineDefs[ NumLineDefs - 2].end = NumVertexes - 4;
  2039.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 4;
  2040.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 1;
  2041.      }
  2042.       }
  2043.       break;
  2044.    case 2:
  2045.       a = 8;
  2046.       b = 128;
  2047.       if (Input2Numbers( -1, -1, "Number of sides", "Radius", 32, 2000, &a, &b))
  2048.       {
  2049.      if (a < 3)
  2050.         a = 3;
  2051.      if (b < 8)
  2052.         b = 8;
  2053.      InsertPolygonVertices( xpos, ypos, a, b);
  2054.      if (sector < 0)
  2055.         InsertObject( OBJ_SECTORS, -1, 0, 0);
  2056.      for (n = 0; n < a; n++)
  2057.      {
  2058.         InsertObject( OBJ_LINEDEFS, -1, 0, 0);
  2059.         LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs;
  2060.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2061.         if (sector >= 0)
  2062.            SideDefs[ NumSideDefs - 1].sector = sector;
  2063.      }
  2064.      ObjectsNeeded( OBJ_LINEDEFS, 0);
  2065.      if (sector >= 0)
  2066.      {
  2067.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 1;
  2068.         LineDefs[ NumLineDefs - 1].end = NumVertexes - a;
  2069.         for (n = 2; n <= a; n++)
  2070.         {
  2071.            LineDefs[ NumLineDefs - n].start = NumVertexes - n;
  2072.            LineDefs[ NumLineDefs - n].end = NumVertexes - n + 1;
  2073.         }
  2074.      }
  2075.      else
  2076.      {
  2077.         LineDefs[ NumLineDefs - 1].start = NumVertexes - a;
  2078.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 1;
  2079.         for (n = 2; n <= a; n++)
  2080.         {
  2081.            LineDefs[ NumLineDefs - n].start = NumVertexes - n + 1;
  2082.            LineDefs[ NumLineDefs - n].end = NumVertexes - n;
  2083.         }
  2084.      }
  2085.       }
  2086.       break;
  2087.    case 3:
  2088.    case 4:
  2089.    case 5:
  2090. /*
  2091.       a = 6;
  2092.       b = 16;
  2093.       if (Input2Numbers( -1, -1, "Number of steps", "Step height", 32, 48, &a, &b))
  2094.       {
  2095.      if (a < 2)
  2096.         a = 2;
  2097.      ObjectsNeeded( OBJ_SECTORS, 0);
  2098.      n = Sectors[ sector].ceilh;
  2099.      h = Sectors[ sector].floorh;
  2100.      if (a * b < n - h)
  2101.      {
  2102.         Beep();
  2103.         Notify( -1, -1, "The stairs are too high for this Sector", NULL);
  2104.         return;
  2105.      }
  2106.      xpos = xpos - 32;
  2107.      ypos = ypos - 32 * a;
  2108.      for (n = 0; n < a; n++)
  2109.      {
  2110.         InsertObject( OBJ_VERTEXES, -1, xpos, ypos);
  2111.         InsertObject( OBJ_VERTEXES, -1, xpos + 64, ypos);
  2112.         InsertObject( OBJ_VERTEXES, -1, xpos + 64, ypos + 64);
  2113.         InsertObject( OBJ_VERTEXES, -1, xpos, ypos + 64);
  2114.         ypos += 64;
  2115.         InsertObject( OBJ_SECTORS, sector, 0, 0);
  2116.         h += b;
  2117.         Sectors[ NumSectors - 1].floorh = h;
  2118.  
  2119.         InsertObject( OBJ_LINEDEFS, -1, 0, 0);
  2120.         LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs;
  2121.         LineDefs[ NumLineDefs - 1].sidedef2 = NumSideDefs + 1;
  2122.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2123.         SideDefs[ NumSideDefs - 1].sector = sector;
  2124.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2125.  
  2126.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  2127.         LineDefs[ NumLineDefs - 4].start = NumVertexes - 4;
  2128.         LineDefs[ NumLineDefs - 4].end = NumVertexes - 3;
  2129.         LineDefs[ NumLineDefs - 3].start = NumVertexes - 3;
  2130.         LineDefs[ NumLineDefs - 3].end = NumVertexes - 2;
  2131.         LineDefs[ NumLineDefs - 2].start = NumVertexes - 2;
  2132.         LineDefs[ NumLineDefs - 2].end = NumVertexes - 1;
  2133.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 1;
  2134.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 4;
  2135.     }
  2136.       }
  2137.       break;
  2138. */
  2139.    case 6:
  2140.      NotImplemented();
  2141.      break;
  2142.    }
  2143. }
  2144.  
  2145.  
  2146.  
  2147. /*
  2148.    menu of miscellaneous operations
  2149. */
  2150.  
  2151. void MiscOperations( int x0, int y0, int objtype, SelPtr *list) /* SWAP! */
  2152. {
  2153.    char   msg[ 80];
  2154.    int    val;
  2155.    int    angle, scale;
  2156.  
  2157.    sprintf( msg, "Rotate and scale %s", GetEditModeName( objtype));
  2158.    if (objtype == OBJ_VERTEXES)
  2159.    {
  2160.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2161.              "Find first free tag number",
  2162.              msg,
  2163.              "Delete Vertex and join LineDefs",
  2164.              "Merge several Vertices into one",
  2165.              "Add a LineDef and split Sector",
  2166.              NULL);
  2167.    }
  2168.    else if (objtype == OBJ_LINEDEFS)
  2169.    {
  2170.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2171.              "Find first free tag number",
  2172.              msg,
  2173.              "Split LineDef (add new Vertex)",
  2174.              "Split LineDefs and Sector",
  2175.              "Flip LineDef",
  2176.              "Swap SideDefs",
  2177.              "Align textures (Y offset)",
  2178.              NULL);
  2179.    }
  2180.    else if (objtype == OBJ_SECTORS)
  2181.    {
  2182.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2183.              "Find first free tag number",
  2184.              msg,
  2185.              "Make door from Sector",
  2186.              "Make lift from Sector",
  2187.              NULL);
  2188.    }
  2189.    else
  2190.    {
  2191.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2192.              "Find first free tag number",
  2193.              msg,
  2194.              NULL);
  2195.    }
  2196.    if (val > 1 && *list == NULL)
  2197.    {
  2198.       Beep();
  2199.       sprintf( msg, "You must select at least one %s", GetObjectTypeName( objtype));
  2200.       Notify( -1, -1, msg, NULL);
  2201.       return;
  2202.    }
  2203.    switch (val)
  2204.    {
  2205.    case 1:
  2206.       sprintf( msg, "First free tag number: %d", FindFreeTag());
  2207.       Notify( -1, -1, msg, NULL);
  2208.       break;
  2209.    case 2:
  2210.       if ((objtype == OBJ_THINGS || objtype == OBJ_VERTEXES) && (*list)->next == NULL)
  2211.       {
  2212.      Beep();
  2213.      sprintf( msg, "You must select more than one %s", GetObjectTypeName( objtype));
  2214.      Notify( -1, -1, msg, NULL);
  2215.      return;
  2216.       }
  2217.       angle = 0;
  2218.       scale = 100;
  2219.       if (Input2Numbers( -1, -1, "rotation angle (°)", "scale (%)", 360, 1000, &angle, &scale))
  2220.      RotateAndScaleObjects( objtype, *list, (double) angle * 0.0174533, (double) scale * 0.01);
  2221.       break;
  2222.    case 3:
  2223.       if (objtype == OBJ_VERTEXES)
  2224.       {
  2225.      DeleteVerticesJoinLineDefs( *list);
  2226.      ForgetSelection( list);
  2227.       }
  2228.       else if (objtype == OBJ_LINEDEFS)
  2229.       {
  2230.      SplitLineDefs( *list);
  2231.       }
  2232.       else if (objtype == OBJ_SECTORS)
  2233.       {
  2234.      if ((*list)->next != NULL)
  2235.      {
  2236.         Beep();
  2237.         Notify(-1, -1, "You must select exactly one Sector", NULL);
  2238.      }
  2239.      else
  2240.      {
  2241.         MakeDoorFromSector( (*list)->objnum);
  2242.      }
  2243.       }
  2244.       break;
  2245.    case 4:
  2246.       if (objtype == OBJ_VERTEXES)
  2247.       {
  2248.      MergeVertices( list);
  2249.       }
  2250.       else if (objtype == OBJ_LINEDEFS)
  2251.       {
  2252.      if ((*list)->next == NULL || (*list)->next->next != NULL)
  2253.      {
  2254.         Beep();
  2255.         Notify(-1, -1, "You must select exactly two LineDefs", NULL);
  2256.      }
  2257.      else
  2258.      {
  2259.         SplitLineDefsAndSector( (*list)->objnum, (*list)->next->objnum);
  2260.         ForgetSelection( list);
  2261.      }
  2262.       }
  2263.       else if (objtype == OBJ_SECTORS)
  2264.       {
  2265.      if ((*list)->next != NULL)
  2266.      {
  2267.         Beep();
  2268.         Notify(-1, -1, "You must select exactly one Sector", NULL);
  2269.      }
  2270.      else
  2271.      {
  2272.         MakeLiftFromSector( (*list)->objnum);
  2273.      }
  2274.       }
  2275.       break;
  2276.    case 5:
  2277.       if (objtype == OBJ_VERTEXES)
  2278.       {
  2279.      if ((*list)->next == NULL || (*list)->next->next != NULL)
  2280.      {
  2281.         Beep();
  2282.         Notify(-1, -1, "You must select exactly two Vertices", NULL);
  2283.      }
  2284.      else
  2285.      {
  2286.         SplitSector( (*list)->objnum, (*list)->next->objnum);
  2287.         ForgetSelection( list);
  2288.      }
  2289.       }
  2290.       else if (objtype == OBJ_LINEDEFS)
  2291.       {
  2292.      FlipLineDefs( *list, TRUE);
  2293.       }
  2294.       break;
  2295.    case 6:
  2296.       if (objtype == OBJ_LINEDEFS)
  2297.       {
  2298.      if (Expert || Confirm( -1, -1, "Warning: the Sector references are also swapped", "You may get strange results if you don't know what you are doing..."))
  2299.         FlipLineDefs( *list, FALSE);
  2300.       }
  2301.       break;
  2302.    case 7:
  2303.       if (objtype == OBJ_LINEDEFS)
  2304.       {
  2305.      SelPtr sdlist, cur;
  2306.  
  2307.      /* select all SideDefs */
  2308.      ObjectsNeeded( OBJ_LINEDEFS);
  2309.      sdlist = NULL;
  2310.      for (cur = (*list)->next; cur; cur = cur->next)
  2311.      {
  2312.         if (LineDefs[ cur->objnum].sidedef1 >= 0)
  2313.            SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef1);
  2314.         if (LineDefs[ cur->objnum].sidedef2 >= 0)
  2315.            SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef2);
  2316.      }
  2317.      if (LineDefs[ (*list)->objnum].sidedef1 >= 0)
  2318.         SelectObject( &sdlist, LineDefs[ (*list)->objnum].sidedef1);
  2319.      if (LineDefs[ (*list)->objnum].sidedef2 >= 0)
  2320.         SelectObject( &sdlist, LineDefs[ (*list)->objnum].sidedef2);
  2321.      /* align the textures */
  2322.      AlignTextures( &sdlist);
  2323.       }
  2324.    }
  2325. }
  2326.  
  2327.  
  2328.  
  2329. /*
  2330.    display a "Preferences" menu (change defaul textures, etc.)
  2331. */
  2332.  
  2333. void Preferences( int x0, int y0)
  2334. {
  2335.    char   *menustr[ 30];
  2336.    int     dummy[ 30];
  2337.    int     n, val;
  2338.    char    texname[ 9];
  2339.  
  2340.    if (x0 < 0)
  2341.       x0 = (ScrMaxX - 50 * 8 - 19) / 2;
  2342.    if (y0 < 0)
  2343.       y0 = (ScrMaxY - 5 * 10 - 28) / 2;
  2344.    for (n = 0; n < 6; n++)
  2345.       menustr[ n] = GetMemory( 80);
  2346.    sprintf( menustr[ 5], "Preferences");
  2347.    sprintf( menustr[ 0], "Change default wall texture    (Current: %s)", DefaultWallTexture);
  2348.    sprintf( menustr[ 1], "Change default floor texture   (Current: %s)", DefaultFloorTexture);
  2349.    sprintf( menustr[ 2], "Change default ceiling texture (Current: %s)", DefaultCeilingTexture);
  2350.    sprintf( menustr[ 3], "Change default floor height    (Current: %d)", DefaultFloorHeight);
  2351.    sprintf( menustr[ 4], "Change default ceiling height  (Current: %d)", DefaultCeilingHeight);
  2352.    val = DisplayMenuArray( x0, y0, menustr[ 5], 5, NULL, menustr, dummy);
  2353.    for (n = 0; n < 6; n++)
  2354.       FreeMemory( menustr[ n]);
  2355.    switch (val)
  2356.    {
  2357.    case 1:
  2358.       strcpy( texname, DefaultWallTexture);
  2359.       ChooseWallTexture( x0 + 42, y0 + 34, "Choose a wall texture", NumWTexture, WTexture, texname);
  2360.       if (strlen( texname) > 0)
  2361.      strcpy( DefaultWallTexture, texname);
  2362.       break;
  2363.    case 2:
  2364.       strcpy( texname, DefaultFloorTexture);
  2365.       ChooseFloorTexture( x0 + 42, y0 + 44, "Choose a floor texture", NumFTexture, FTexture, texname);
  2366.       if (strlen( texname) > 0)
  2367.      strcpy( DefaultFloorTexture, texname);
  2368.       break;
  2369.    case 3:
  2370.       strcpy( texname, DefaultCeilingTexture);
  2371.       ChooseFloorTexture( x0 + 42, y0 + 54, "Choose a ceiling texture", NumFTexture, FTexture, texname);
  2372.       if (strlen( texname) > 0)
  2373.      strcpy( DefaultCeilingTexture, texname);
  2374.       break;
  2375.    case 4:
  2376.       val = InputIntegerValue( x0 + 42, y0 + 64, -512, 511, DefaultFloorHeight);
  2377.       if (val >= -512)
  2378.      DefaultFloorHeight = val;
  2379.       break;
  2380.    case 5:
  2381.       val = InputIntegerValue( x0 + 42, y0 + 74, -512, 511, DefaultCeilingHeight);
  2382.       if (val >= -512)
  2383.      DefaultCeilingHeight = val;
  2384.       break;
  2385.    }
  2386. }
  2387.  
  2388.  
  2389.  
  2390. /* end of file */
  2391.